这里有两件事有效。我们可以实例化一个转发函数模板来获取一个带左值的函数指针:
template <class T>
void f(T &&) {}
void(*p)(int &) = f; // Cool!
我们还可以将采用左值的非捕获通用 lambda 转换为采用左值的函数指针:
auto l = [](auto &) { };
void (*lp)(int &) = l; // Still cool!
但显然 GCC 和 Clang 都不会将转发通用 lambda 转换为采用左值的函数指针:
auto l = [](auto &&) { };
void (*lp)(int &) = l; // Not cool!
GCC 输出:
<source>:9:21: error: invalid user-defined conversion from '<lambda(auto:1&&)>' to 'void (*)(int&)' [-fpermissive]
void (*lp)(int &) = l;
^
叮当输出:
<source>:9:8: fatal error: no viable conversion from '(lambda at <source>:7:10)' to 'void (*)(int &)'
void (*lp)(int &) = l;
^ ~
<source>:7:10: note: candidate template ignored: could not match 'type-parameter-0-0 &&' against 'int &'
auto l = [](auto &&) { };
^
尽管可以从转发 lambda 中获取采用左值的成员函数指针,但仍然如此:
auto lmp = &decltype(l)::operator()<int &>;
template <class...>
struct check;
check<decltype(lmp)> c;
...void (<lambda(auto:1&&)>::*)(int&) const
按预期输出类型。
我认为引用折叠规则是任何模板实例化所固有的,并希望它能够工作。Clang 和 GCC 是否都有错误,或者标准实际上没有提供错误?