使用模板调用运算符和通用Lambda重载结构-GCC与Clang [英] Overloading structs with template call operator and generic lambdas - gcc vs clang
问题描述
我发现了一个代码片段,可以在 clang ++ 4(和主干)中编译并正常工作,但是无法在 g ++ 7(和主干)中进行编译.假设我具有以下struct
类型:
I have discovered a code snippet that compiles and works properly in clang++ 4 (and trunk) but fails to compile in g++ 7 (and trunk). Let's assume I have the following struct
types:
struct a { void foo() { } };
struct b { void bar() { } };
struct c { void bar() { } };
我想从显式处理a
的lambda中创建一个过载集,而b
和c
被使用auto
参数的通用lambda捕获":
I want to create an overload set out of lambdas which handles a
explicitly, while b
and c
are "caught" with a generic lambda using an auto
parameter:
auto ol = overload([](a x) { x.foo(); },
[](auto x){ x.bar(); })
当我调用ol(a{})
时:
-
clang ++ 编译并按预期方式运行:
a
匹配"第一个lambda,而b
和c
匹配第二个lambda.
clang++ compiles and behaves as expected:
a
"matches" the first lambda, whileb
andc
match the second one.
g ++ 编译失败,出现以下错误:
g++ fails to compile, with the following error:
error: 'struct a' has no member named 'bar'
[](auto x){ x.bar(); };
~~^~~
似乎编译器尝试实例化第二个lambda,即使第一个lambda可以更好地匹配.希望这是一个错误,对我来说似乎不直观.
It seems that the compiler tries to instantiate the second lambda even though the first one is a way better match. Hopefully this is a bug, as it seems unintuitive to me.
请注意,如果我使用一些老式的struct
实例代替 lambda表达式,则两个编译器都可以正常工作:
Note both compilers work properly if instead of lambda expressions I use some old-fashioned struct
instances:
struct s0
{
auto operator()(a x) const { x.foo(); }
};
struct s1
{
template <typename T>
auto operator()(T x) const { x.bar(); }
};
auto os = overload(s0{}, s1{});
os(a{}); // OK!
我希望lambda大致等于s0
和s1
,所以这更加令人惊讶.
I would expect the lambdas to be roughly equivalent to s0
and s1
, so this is even more surprising.
这是我产生过载集的方式:
This is the way I'm producing the overload set:
template <typename... Fs>
struct overloader : Fs...
{
template <typename... FFwds>
overloader(FFwds&&... fs) : Fs{std::forward<FFwds>(fs)}...
{
}
using Fs::operator()...;
};
template <typename... Fs>
auto overload(Fs&&... fs)
{
return overloader<std::decay_t<Fs>...>{std::forward<Fs>(fs)...};
}
这是gcc.godbolt.org
上的 实时示例,显示了不同的地方编译器之间的行为.
And here's a live example on gcc.godbolt.org
, showing the different behavior between the compilers.
这是g ++错误吗?或者在这种情况下,标准中是否存在某些使lambda行为不同于struct
实例的行为?
Is this a g++ bug? Or is there something in the standard that makes lambdas behave differently from struct
instances in this situation?
推荐答案
我认为这是gcc错误(提交为:
I think this is a gcc bug (submitted as 80767), running afoul of [temp.inst]/9:
实现不得隐式实例化函数模板,变量模板,成员模板,非虚拟成员函数,成员类,类模板的静态数据成员或constexpr if语句的子语句,除非需要这样的实例化.
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement, unless such instantiation is required.
不需要用auto = a
实例化通用lambda的operator()
,因此不应实例化.
The instantiation of the generic lambda's operator()
with auto = a
is not required, hence it should not be instantiated.
这篇关于使用模板调用运算符和通用Lambda重载结构-GCC与Clang的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!