gcc vs clang - ambiguous overload when using `make_overload` variadic lambda inheritance [duplicate]

ぐ巨炮叔叔 提交于 2019-12-06 02:55:07

I can give you a workaround.

template <typename... TFs>
struct overload_set : TFs...
{
  overload_set(TFs... fs) : TFs(fs)... {}
};

here, we inherit from a bunch of distinct parent types, each with an operator(). These do not (at least in gcc) overload the way you want.

To fix this, we inherit linearly and carry () down via using:

template<class...Ts>
struct inherit_linearly;
template<>
struct inherit_linearly<>{};
template<class T0, class...Ts>
struct inherit_linearly<T0, Ts...>:
  T0, inherit_linearly<Ts...>
{
   using T0::operator();
   using inherit_linearly<Ts...>::operator();
   template<class A0, class...As>
   inherit_linearly( A0&&a0, As&&...as ):
     T0(std::forward<A0>(a0)),
     inherit_linearly<Ts>(std::forward<As>(as)...) 
   {}
};

now we replace overload_set as follows:

template <typename... TFs>
struct overload_set : inherit_linearly<TFs...>
{
  using inherit_linearly<TFs...>::operator();
  overload_set(TFs... fs) :
    inherit_linearly<TFs...>(std::forward<TFs>(fs)...)
  {}
};

and both gcc and clang should like it.

The linear inheritance is sub-optimal: a balanced binary tree is better, but would take more work. (basically, you take a pack Xs... and you split it into Xs_front... and Xs_back... using careful TMP, put those in a types<...> pack, transcribe those to your two parents, and do the using blah::operator() thing). This is because the compiler has a limit on recursive template instantiations and inheritance depth that tends to be more shallow than the limit of total template instantiations and inheritance "volume".


In we don't have to do this linear inheritance:

template <typename... TFs>
struct overload_set : TFs...
{
  using TFs::operator()...;
  overload_set(TFs... fs) : TFs(fs)... {}
};

because they added a new spot you can do ... expansion.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!