为什么我不能以`void(*func)(T&&)`和`for (T&& v : vec)`这样的方式使用通用引用?

问题描述 投票:0回答:1

我试图在函数指针和基于范围的 for 循环中使用通用引用。

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;
}

代码无法编译并给出:

Error C2672 'forward': no matching overloaded function found
Error C2440 'initializing': cannot convert from 'const int' to 'int &&'

我试过了

template<typename T>
void ForEach(const vector<T> vec, void(*func)(const T&)) {
    for (const T& val : vec)
    {
        func(val);
    }
}

这次代码编译并正常工作。

c++ templates perfect-forwarding forwarding-reference
1个回答
0
投票

转发引用仅在直接应用于推导的模板参数时才会出现。您的函数指针并非如此。

转发引用不是“真实”类型。它们是模板类型推导工作方式的一个技巧。转发引用的工作方式是根据传递给它们的表达式的值类别推导不同的类型。

也就是说,给定一个像

这样的函数
template <typename T>
void func(T&& arg);

当您调用

func(some_lvalue)
时,
T
会被推断为
int&
。这使得
func
的参数成为
int& &&
。由于您无法引用引用,因此将应用引用折叠规则,并且
arg
的类型折叠为
int&

另一方面,如果您调用

func(42)
T
会被推算为
int
,而
arg
的类型仍为
int&&

© www.soinside.com 2019 - 2024. All rights reserved.