我有一个带有通用(转发)参数的模板函数,如下所示:
#include <iostream>
#include <type_traits>
template <typename T>
void foo(T&& arg)
{
// Check the type of T
if constexpr (std::is_lvalue_reference_v<T>) {
std::cout << "T is an lvalue reference" << std::endl;
} else if constexpr (std::is_rvalue_reference_v<T>) {
std::cout << "T is an rvalue reference" << std::endl;
} else {
std::cout << "T is neither lvalue nor rvalue reference" << std::endl;
}
}
int main()
{
foo(10);
return 0;
}
在这段代码中,我有一个函数模板 foo ,它带有一个名为 arg 的通用(转发)引用参数。该函数的目的是检查模板参数T的类型。
在主函数中,我使用参数 10 调用 foo。由于 10 是右值,所以我希望结果为“T 是右值引用”。但是,当我使用
g++ -std=c++17 -Wall -pthread -fno-elide-constructors -Qn main.cpp && ./a.out
标志在“http://coliru.stacked-crooked.com/”在线编译器中编译并运行此代码时,实际输出是 T is neither lvalue nor rvalue reference.
我的假设是模板类型
T
在这里将被推导为int&&
。但我猜结果是 int
,这与 decltype(10)
的行为类似。这里的类型推导和调用decltype(X)
一样吗?或者说这里面有什么规则吗?
此外:
如果按如下方式调用 foo,
int x = 10;
foo(std::move(x));
结果是
T is neither lvalue nor rvalue reference
?我期待T is an rvalue reference
您正在检查
T
是否是右值引用,而您应该检查 T&&
是否是右值引用。
参数类型(可以是左值引用或右值引用)拼写为
T&&
。
通过此修复,您也将永远达到
std::cout << "T&& is neither lvalue nor rvalue reference" << std::endl;
不可能
T&&
不可以作为参考。
只有一个例外,模板类型参数不会被推导为引用类型,也永远不会被推导为右值引用。
唯一一个例外是通用引用起作用的原因:当函数模板接受
T&&
形式的参数时,如果左值作为该参数传递,则 T
被推导为左值引用类型。
所以在你的例子中:
foo(10)
,T
被推断为 int
。 这使得类型为 arg
int&&
。foo(some_int)
,T
被推断为 int&
。 这意味着 arg
的类型将是 int& &&
。 由于您无法引用引用,因此将应用引用折叠规则,并且 int& &&
折叠为 int&
。