I'm trying to use a universal reference in a callback function pointer and range-based for loop.
template<typename T>
void PrintFunc(const T& value) {
cout << value << "\n";
}
template<typename T>
void PrintFunc(T&& value) {
cout << value << "\n";
};
template<typename T>
void ForEach(const vector<T> vec, void(*func)(T&&)) {
for (T&& val : vec)
{
func(std::forward(val));
}
}
int main() {
vector<int> v{ 1, 2, 3 };
ForEach<int>(v, PrintFunc<int>);
return 0;
}
The code fails to compile:
Error C2672 'forward': no matching overloaded function found
Error C2440 'initializing': cannot convert from 'const int' to 'int &&'
I tried:
template<typename T>
void ForEach(const vector<T> vec, void(*func)(const T&)) {
for (const T& val : vec)
{
func(val);
}
}
And this time the code compiles and works properly.
Forwarding references only arise when applied directly to a deduced template parameter. That isn't the case with your function pointer.
Forwarding references aren't a "real" type. They're a trick of the way template type deduction works. The way forwarding references work is by deducing different types depending on the value category of the expression passed to them.
That is, given a function like:
When you call
func(some_lvalue), wheresome_lvalueis anint,Tgets deduced asint&. That leavesfunc's parameter as anint& &&. Since you can't have references to references, the reference collapsing rules are applied, and the type ofargcollapses toint&.On the other hand, if you call
func(42),Tgets deduced asint, leaving the type ofargasint&&.For users not familiar with this stuff, see the old term "Universal References" coined by Scott Meyers documented on isocpp and this video:
C++ and Beyond 2012: Scott Meyers - Universal References in C++11.