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

时间:2013-02-17 07:40:36

标签: c++ c++11

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

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

template<class T> void function(T&& t){/*SNIP*/}

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

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

void function(Class& t){/*SNIP*/}
void function(Class&& t){ function(t); }

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

编辑:问题解决了。你们两个都回答得很好。我已经对两个答案都投了+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&&){}

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

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

用法示例:

template< uRefType(T, Class) > void function(T&&){}

2 个答案:

答案 0 :(得分:4)

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

因此,如果你有一个功能模板

template <typename T>
void fun(T &&)
{ /*...*/ }

并且您希望确保仅在T是特定类型时定义它,您可以使用enable_if<...>::type构造而不是返回类型(此处为void)。然后将布尔条件A定义为: Tint ,类型B定义为原始返回类型功能(这里,void)。

因此,如果我们只想在funT时定义int,我们就会明白:

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

注意布尔条件如何定义如下(省略std::以获得更好的可读性):

is_same<int,typename decay<T>::type>::value

decay语句用于确保无论Tint还是int &(还有一些特殊情况)都能正常运行。


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

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

template <typename T>
void fun(T &&obj)
{ other_fun(std::forward<T>(obj)); }

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

答案 1 :(得分:1)

std::enable_if使用std::is_same

template<class T, 
         class = typename std::enable_if<std::is_same<float, T>::value>::type>
void function(T&& t){/*SNIP*/}

(正如jogojapan的答案中首次提到的,我忘了提及)在T上使用std::decay,因为T&T的类型不同, const T与T`:

不同
template<
  class T, 
  class = typename std::enable_if<
                       std::is_same<float,
                                    typename std::decay<T>::type>::value>::type>
void function(T&& t){/*SNIP*/}

请参阅http://ideone.com/ztkHsf上的演示。