【问题标题】:C++11 : How can I define a function that accept a universal reference of a specific type of object?C++11:如何定义一个接受特定类型对象的通用引用的函数?
【发布时间】:2013-02-17 07:40:36
【问题描述】:

问题: 我正在用 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&&){}

【问题讨论】:

  • 您提出的解决方案不保留右值性。你的意思是void function(Class&amp;&amp; t){/*COPY OF SNIP*/}

标签: c++ c++11


【解决方案1】:

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

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

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

如果你想确保它只在T 是特定类型时被定义,你可以使用enable_if&lt;...&gt;::type 构造而不是返回类型(这里是void)。然后将布尔条件A 定义为类似:Tint,类型B 被定义为函数的原始返回类型(此处为void )。

因此,如果我们希望仅当 Tint 时才定义 fun,我们会得到:

#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 &amp;(以及一些其他特殊情况)都可以正常工作。


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

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

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

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

【讨论】:

    【解决方案2】:

    std::enable_ifstd::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&amp;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 上查看演示。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多