C++ 11:如何定义一个接受特定类型对象的通用引用的函数?

Kon*_*lex 5 c++ c++11

问题:我正在用C++ 11开发一个程序.我想写一个接受右值引用和左值引用的函数.(即普遍参考).

以下函数接受通用引用参数:

template<class T> void function(T&& t){/*SNIP*/}
Run Code Online (Sandbox Code Playgroud)

但是,它接受所有类型的参数.它破坏了功能的类型安全性.如果我希望它接受特定类型的参数,我该怎么办?

这是我能想到的解决方案:

void function(Class& t){/*SNIP*/}
void function(Class&& t){ function(t); }
Run Code Online (Sandbox Code Playgroud)

但是,它很难看.如果我想更改要接受的参数,或更改函数名称,我必须更新该函数的两个版本.它有比这更好的等价物吗?

编辑:问题解决了.你们两个都回答得很好.我已经对两个答案都投了+1,以表达我的感激之情.我将把这个问题留下几天.得票最多的答案将被接受.

EDIT2:我最终得到以下代码:

template < class T,
class=typename std::enable_if<std::is_same<Class, typename std::decay<T>::type>::value>::type //Dummy template parameter
>
void function(T&&){}
Run Code Online (Sandbox Code Playgroud)

EDIT3:我为此编写了一个宏定义:

#define uRefType(T, typeLimit) class T, class=typename std::enable_if<std::is_same<typename std::decay<T>::type, typeLimit>::value>::type
Run Code Online (Sandbox Code Playgroud)

用法示例:

template< uRefType(T, Class) > void function(T&&){}
Run Code Online (Sandbox Code Playgroud)

jog*_*pan 6

一种方法是使用std::enable_if. 这是标头提供的结构type_traits。它的定义方式是布尔条件在编译时计算结果为 true 时enable_if<A,B>::type的类型。否则它是空的。BA

因此,如果你有一个函数模板

template <typename T>
void fun(T &&)
{ /*...*/ }
Run Code Online (Sandbox Code Playgroud)

并且您想确保它仅在T是某种类型时才定义,您可以使用enable_if<...>::type构造而不是返回类型(此处为void)。然后,布尔条件A被定义为类似:Tisint,并且类型B被定义为函数的原始返回类型(此处为void)。

因此,如果我们只想在isfun时被定义,我们会得到:Tint

#include <type_traits>

template <typename T>
typename std::enable_if<std::is_same<int,typename std::decay<T>::type>::value,void>::type
fun(T &&)
{ }

int main()
{
  int    lvali = 3;
  double lvald = 3.3;

  fun(3);
  fun(lvali);

  // fun(3.3);      // this won't be accepted (not an int)
  // fun(lvald)     // this won't be accepted (not an int)

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

请注意布尔条件的定义如下(std::为了更好的可读性省略了 to ):

is_same<int,typename decay<T>::type>::value
Run Code Online (Sandbox Code Playgroud)

decay语句用于确保无论Tintor int &(以及一些更特殊的情况)都可以正常工作。


进一步说明:只有当所讨论的函数的定义对于右值和左值相同时,这种技巧才真正有用。在许多情况下,情况并非如此(因为右值情况将实现移动,左值不会,或类似的情况)。

两个定义实际上相同的典型情况是函数体非常短并且除了将参数转发到另一个(可能重载)函数调用之外什么也不做:

template <typename T>
void fun(T &&obj)
{ other_fun(std::forward<T>(obj)); }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,不使用任何或其他技巧可能是可以的enable_if,因为 的声明other_fun将确保最终只接受某些类型。