gcc vs clang - 使用`make_overload`变量lambda继承时的不明确的重载 [英] gcc vs clang - ambiguous overload when using `make_overload` variadic lambda inheritance
问题描述
另一轮 clang vs gcc 的时间。 在godbolt.org上的实例。
测试0 :重载的可调用对象
struct Trad
{
auto operator()(int) { return 1; }
auto operator()(float) { return 2; }
auto operator()(double) { return 3; }
};
int main()
{
assert(Trad{}(1) == 1);
assert(Trad{}(1.f) == 2);
assert(Trad{}(1.0) == 3);
}
- g ++ 5.2编译并运行。 >
- clang ++ 3.5 (及更高版本)编译并运行。
- g++ 5.2 compiles and run.
- clang++ 3.5 (and later versions) compiles and run.
测试1 :重载的可呼叫对象lambda继承
Test 1: overloaded callable object, generated via lambda inheritance
template <typename... TFs>
struct overload_set : TFs...
{
overload_set(TFs... fs) : TFs(fs)... {}
};
template <typename... TFs>
auto overload(TFs&&... fs)
{
return overload_set<TFs...>{fs...};
}
int main()
{
auto func = overload
(
[](int) { return 1; },
[](float) { return 2; },
[](double) { return 3; }
);
assert(func(1) == 1);
assert(func(1.f) == 2);
assert(func(1.0) == 3);
}
-
g ++ 5.2无法编译。
g++ 5.2 does not compile.
错误:对成员operator()的请求不明确
error: request for member 'operator()' is ambiguous
clang ++ 3.5 (及更高版本)
clang++ 3.5 (and later versions) compiles and run.
推荐答案
我可以给你一个解决方法。
I can give you a workaround.
template <typename... TFs>
struct overload_set : TFs...
{
overload_set(TFs... fs) : TFs(fs)... {}
};
这里,我们继承了一系列不同的父类型,每个类型都有一个 operator()
。
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)...)
{}
};
现在我们替换 overload_set
如下: / p>
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)...)
{}
};
gcc和clang都应该喜欢。
and both gcc and clang should like it.
线性继承是次优的:平衡的二叉树更好,但需要更多的工作。 (基本上,你拿一包 Xs ...
,然后将它拆分为 Xs_front ...
和 Xs_back ...
使用仔细的TMP,将它们放在 types< ...>
,并使用blah :: operator()做)。这是因为编译器对递归模板实例化和继承深度的限制往往比总模板实例化和继承volume的限制更浅。
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".
这篇关于gcc vs clang - 使用`make_overload`变量lambda继承时的不明确的重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!