C++ 使用模板调用运算符和通用lambdas重载结构-gcc vs clang
我发现了一个代码片段,它在clang++4(和trunk)中编译并正常工作,但在g++7(和trunk)中编译失败。假设我有以下C++ 使用模板调用运算符和通用lambdas重载结构-gcc vs clang,c++,lambda,overloading,language-lawyer,c++17,C++,Lambda,Overloading,Language Lawyer,C++17,我发现了一个代码片段,它在clang++4(和trunk)中编译并正常工作,但在g++7(和trunk)中编译失败。假设我有以下struct类型: struct a { void foo() { } }; struct b { void bar() { } }; struct c { void bar() { } }; 我想创建一个lambda的重载集,它显式地处理a,而b和c使用auto参数用通用lambda“捕获”: auto ol = overload([](a x) { x.foo
struct
类型:
struct a { void foo() { } };
struct b { void bar() { } };
struct c { void bar() { } };
我想创建一个lambda的重载集,它显式地处理a
,而b
和c
使用auto
参数用通用lambda“捕获”:
auto ol = overload([](a x) { x.foo(); },
[](auto x){ x.bar(); })
当我调用ol(a{})
时:
- clang++按预期编译和运行:
与第一个lambda“匹配”,而a
和b
与第二个lambda匹配c
- g++编译失败,出现以下错误:
编译器似乎试图实例化第二个lambda,尽管第一个lambda更匹配。希望这是一个bug,因为它对我来说似乎不直观error: 'struct a' has no member named 'bar' [](auto x){ x.bar(); }; ~~^~~
注意:如果我使用一些老式的
struct
实例而不是lambda表达式,则这两个编译器都能正常工作:
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!
下面是一个示例,显示了编译器之间的不同行为
这是一个g++错误吗?或者标准中有什么东西使得lambda在这种情况下的行为与
struct
实例不同吗?我认为这是一个gcc错误(提交为),与以下内容相冲突:
除非需要实例化,否则实现不应隐式实例化函数模板、变量模板、成员模板、非虚拟成员函数、成员类、类模板的静态数据成员或constexpr if语句的子语句
不需要使用
auto=a
实例化通用lambda的运算符()
,因此不应实例化它 嗯,何时使用…
进入标准?C++17?@Nirfiedman Yep,在C++17中,多亏了旁白:能够将函数指针作为重载的参数是很好的。为此,请将:Fs…
替换为:some\u magic…
,其中some\u magic
检测函数指针并将其映射到存储它的类,以及它保留的所有其他内容。(但这个重载可能是一个简化的MCVE,在这种情况下忽略它)错误来自实例化转换函数模板到函数指针,这意味着这是的另一个版本。
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)...};
}