'Why doesn't `auto &&` behave as a so-called "universal reference" when used as a lambda argument
Why does the && argument type in the following example not behave as a so-called "universal reference" even though it seems to be in a "deduced context", and instead is interpreted as an r-value:
auto main() -> int {
using MyFn = void (*)(int &);
MyFn special = [](auto && thing) {}; // compile error, deduced as int && rather than int&
return 0;
}
Whereas the following, which I expect to be equivalent, does work?
template <typename T> void foo(T &&){};
auto main() -> int {
using MyFn = void (*)(int &);
MyFn specialC = foo;
return 0;
}
I suspect there's some esoteric detail with converting lambdas to function pointers that matters here, but so far I can't figure it out.
Solution 1:[1]
Forwarding references are supported by a special deduction rule. The rule states that if we need to deduce T in order to make T&& identical to U&, then T is deduced as U& (so that T&& will be U& (&&), which just collapses down to U&).
However, this special rule only applies under certain circumstances: when deducing function template template arguments based on the arguments to a function call ([temp.deduct.call]/3) (in the case that the argument is an lvalue of type U, which you can imagine as having the type "U&"), when taking the address of a function template, and when matching a function template specialization declaration against a primary template declaration ([temp.deduct.type]/10).
Your case is none of the above, but is instead a separate case of deducing template arguments for a conversion function template ([temp.deduct.conv]), which doesn't have the special rule for forwarding references.
Another example where the forwarding reference deduction rules don't apply is the following, which will therefore not compile:
template <class T>
void foo(void(*)(T&&)) {}
void bar(int&) {}
int main() {
foo(bar);
}
Solution 2:[2]
In lambda parameters, auto by itself gives universal type deduction. So this does what you want:
MyFn special = [](auto thing) {};
Demo using a non-copyable type to prove it's not passing by value: https://godbolt.org/z/5vfWc6c8x
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Brian Bi |
| Solution 2 | John Zwinck |
