右值和右值引用的模板专用化
template specialization for rvalue and lvalue reference
我在转发方面玩了一下,得到了以下示例,效果很好。
void Func2( int& a, int& b) { cout << "V1" << endl; }
void Func2( int&& a, int& b) { cout << "V2" << endl; }
void Func2( int& a, int&& b) { cout << "V3" << endl; }
void Func2( int&& a, int&& b) { cout << "V4" << endl; }
template < typename T, typename U>
void Func( T&& t, U&& u)
{
X::Func3( std::forward<T>(t), std::forward<U>(u));
Func2( std::forward<T>(t), std::forward<U>(u));
}
int main()
{
int a, b;
Func( a, b);
Func( 1, b);
Func( a, 2);
Func( 1, 2);
return 0;
}
但是我还想有一个函数模板,Func2
用任何类型替换类型int
,或者如果不可能,用专门的方法替换一个类。以下代码片段将无法编译:
class X
{
public:
template < typename T, typename U>
static void Func3( T& t, U& u) { cout << "X1" << endl; }
template < typename T, typename U>
static void Func3( T&& t, U& u) { cout << "X2" << endl; }
template < typename T, typename U>
static void Func3( T& t, U&& u) { cout << "X3" << endl; }
template < typename T, typename U>
static void Func3( T&& t, U&& u) { cout << "X4" << endl; }
};
结果:
main.cpp: In instantiation of 'void Func(T&&, U&&) [with T = int&; U = int&]':
main.cpp:36:18: required from here
main.cpp:29:57: error: call of overloaded 'Func3(int&, int&)' is ambiguous
X::Func3( std::forward<T>(t), std::forward<U>(u));
^
main.cpp:29:57: note: candidates are:
main.cpp:9:29: note: static void X::Func3(T&, U&) [with T = int; U = int]
static void Func3( T& t, U& u) { cout << "X1" << endl; }
^
main.cpp:12:29: note: static void X::Func3(T&&, U&) [with T = int&; U = int]
static void Func3( T&& t, U& u) { cout << "X2" << endl; }
^
main.cpp:15:29: note: static void X::Func3(T&, U&&) [with T = int; U = int&]
static void Func3( T& t, U&& u) { cout << "X3" << endl; }
^
main.cpp:18:29: note: static void X::Func3(T&&, U&&) [with T = int&; U = int&]
static void Func3( T&& t, U&& u) { cout << "X4" << endl; }
^
正如其他答案所说,这些调用是模棱两可的,因为通用引用T&&, U&&
与左值和右值引用匹配。您可以使用std::enable_if
手动删除歧义,例如
template <bool C>
using only_if = typename std::enable_if <C>::type;
template <typename T>
using is_lref = std::is_lvalue_reference <T>;
struct X
{
template <typename T, typename U>
static void
Func3(T& t, U& u) { cout << "X1" << endl; }
template <typename T, typename U>
static only_if <!is_lref <T>()>
Func3(T&& t, U& u) { cout << "X2" << endl; }
template <typename T, typename U>
static only_if <!is_lref <U>()>
Func3(T& t, U&& u) { cout << "X3" << endl; }
template <typename T, typename U>
static only_if <!(is_lref <T>() || is_lref <U>())>
Func3(T&& t, U&& u) { cout << "X4" << endl; }
};
另请参阅实时示例。这样,您明确表示T&&
不应与左值引用匹配。
这种方法很难推广到更多的输入参数。在这种情况下,请考虑一次只处理一个参数,其余参数作为右值引用。因此,您只需要两个重载加上递归调用,但确切的形式取决于您要执行的操作。
以下内容可能会有所帮助:
template <typename T, typename U>
class X
{
public:
static void Func3(T& t, U& u) { cout << "X1" << endl; }
static void Func3(T&& t, U& u) { std::cout << "X2" << std::endl; }
static void Func3(T& t, U&& u) { cout << "X3" << endl; }
static void Func3(T&& t, U&& u) { cout << "X4" << endl; }
};
template <typename T, typename U>
void Func(T&& t, U&& u)
{
X<typename std::decay<T>::type, typename std::decay<U>::type>::Func3( std::forward<T>(t), std::forward<U>(u));
Func2( std::forward<T>(t), std::forward<U>(u));
}
所以 Func3 使用真正的 r 值引用而不是通用引用。
这是因为T&&在模板函数中非常特殊,并且不是右值引用。它被命名为通用引用并绑定到参数的类型。因此,Func3 的多个候选项导致相同的绑定,并且您以不明确的调用结束。
下面的代码显示"true false true",并显示通用引用的行为。
#include <iostream>
#include <type_traits>
template <typename T>
bool foo( T&& v ) {
return std::is_rvalue_reference<decltype(v)>::value;
}
int main() {
std::cout << std::boolalpha;
std::cout << foo( 1 ) << std::endl;
int a{};
std::cout << foo( a ) << std::endl;
std::cout << foo( std::move(a) ) << std::endl;
}
const T&和 T&& 的重载不是一个好的解决方案,因为 T&& 将比 const T& 更匹配。这与非模板函数不同。
#include <iostream>
#include <type_traits>
template <typename T>
bool foo( T&& v ) {
return false;
}
template <typename T>
bool foo( T const & v ) {
return true;
}
bool bar( int&& v ) {
return false;
}
bool bar( int const & v ) {
return true;
}
int main() {
std::cout << std::boolalpha;
int a{};
int const b {};
std::cout << foo( a ) << std::endl; // false
std::cout << foo( b ) << std::endl; // true
std::cout << bar( a ) << std::endl; // true
std::cout << bar( b ) << std::endl; // true
}
相关文章:
- .cpp和.h文件中的模板专用化声明
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 具有常量引用参数的函数模板专用化
- 将返回类型专用化为 void 或 const 左值引用
- 模板专用化会导致未定义的引用错误
- 对专用模板成员的未定义引用
- 通过引用调用模板专用化
- 使用模板专用化来比较指针引用
- 为什么模板别名专用化取决于引用它的上下文
- 静态 constexpr 模板成员在专用时提供未定义的引用
- 共享库:具有部分模板专用化和显式模板实例化的未定义引用
- 专用纯虚拟模板函数(未定义引用)的另一个问题
- 右值和右值引用的模板专用化
- C++ 中的函数模板专用化和右值引用
- qt专用插槽moc未定义引用错误
- std::引用类型的可选专用化
- 无法引用专用静态成员变量:编译器错误