为什么 `auto &&` 在用作 lambda 参数时不充当所谓的“通用引用”

Cat*_*kul 8 c++ lambda templates rvalue c++17

为什么&&以下示例中的参数类型不表现为所谓的“通用引用”,即使它似乎处于“推导上下文”中,而是被解释为右值:

auto main() -> int {    
    using MyFn = void (*)(int &);    
    MyFn special = [](auto && thing) {};  // compile error, deduced as int && rather than int&
    
    return 0;    
}
Run Code Online (Sandbox Code Playgroud)

而我期望等效的以下内容是否有效?

template <typename T> void foo(T &&){};

auto main() -> int {
    using MyFn = void (*)(int &);
    MyFn specialC = foo;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我怀疑将 lambda 转换为函数指针的一些深奥细节在这里很重要,但到目前为止我还无法弄清楚。

Bri*_*ian 8

转发参考文献有特殊的扣除规则支持。该规则指出,如果我们需要进行推导T才能与T&&相同U&,则T被推导为U&(因此T&&将是U& (&&),它只是折叠为U&)。

但是,此特殊规则仅适用于某些情况:根据函数调用的参数 ( [temp.deduct.call]/3 ) 推导函数模板模板参数时(在参数是类型 的左值的情况下U,其中您可以想象为U&在获取函数模板的地址时以及将函数模板专门化声明与主模板声明 ( [temp.deduct.type]/10 ) 进行匹配时具有类型“”)。

您的情况不是上述情况,而是推导转换函数模板([temp.deduct.conv])的模板参数的单独情况,它没有转发引用的特殊规则。

转发引用扣除规则不适用的另一个示例如下,因此不会编译:

template <class T>
void foo(void(*)(T&&)) {}

void bar(int&) {}

int main() {
    foo(bar);
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*nck 0

在 lambda 参数中,auto它本身给出了通用类型推导。所以这就是你想要的:

MyFn special = [](auto thing) {};
Run Code Online (Sandbox Code Playgroud)

使用不可复制类型来证明它不是按值传递的演示: https: //godbolt.org/z/5vfWc6c8x