使用通用引用参数专门化函数模板是否有意义?

时间:2016-09-02 10:26:41

标签: c++ templates c++11

对于模板功能,我们可以按如下方式对其进行专门化:

template <typename T>
void func(T t) {}

// specialization for int
template <>
void func(int t) {}

但是,我不确定如何使用通用引用(来自run-sequence的名称)来专门化模板函数。

// template function with universal reference
template <typename T>
void func(T &&t) {}

我认为简单地将T替换为int并不能使其成为专业化:

template <>
void func(int &&t) {}

由于模板功能可以同时接受左值和右值,而“#”专用&#39;一个人只能接受右值。

我是否还应该定义一个&#39;专业化&#39;左值参考?

// 'specialization' for lvalue reference
template <>
void func(int &t) {}

这两个专业&#39;对原始模板功能进行专门化?或者对它有专业化是否有意义?

2 个答案:

答案 0 :(得分:4)

专业化功能模板很少是个好主意。非常稀有。它看起来像模板类专门化和重载的混合,但两者都没有。

函数有重载。使用那些。

如果重载没有得到您想要的确切行为,请使用基于重载的标记调度的辅助函数,或转发到类。

在这种情况下,它可以像:

一样简单
template <typename T>
void func(T&&){}
void func(int){}

或者:

template<class T>struct tag_t{};
template<class T>constexpr tag_t<T>tag{};
namepsace details{
  template <class T, class U>
  void func(tag_t<T>, U&&){}
  template <class U>
  void func(tag_t<int>, U&&){}
}
template <class T>
void func(T&&t){
  return details::func(tag<std::decay_t<T>>, std::forward<T>(t));
}

答案 1 :(得分:2)

当T与某个类型匹配时,它可以是任何一个(这是一个非详尽的列表):

int
int&
int const&
int&&
int volatile&
int volatile const&

......等等。

在这种情况下专注并没有多大意义,因为我们必须预测和编写符合所有用例的专业化。

但也许func实际上代表了一些可以应用于通用引用的函数的概念。

在这种情况下,我们可能做的是这样的事情:

#include <iostream>

template<class Type>
struct func_op
{
  template<class T> void operator()(T&& t) const
  {
    // default implementation
  }
};

template <typename T>
void func(T&& t) 
{
  func_op<std::decay_t<T>> op;
  return op(std::forward<T>(t));
}


// now specialise the operation for all classes of int

template<>
struct func_op<int>
{
  template<class T> void operator()(T&& t) const
  {
    static_assert(std::is_same<std::decay_t<T>, int>(), 
                  "not an int!");
    std::cout << "some kind of operation on int" << t << std::endl;
  }
};



int main()
{
  int a = 5;
  const int b = 6;
  const volatile int c = 7;
  volatile int d = 8;
  func(a);
  func(b);
  func(c);
  func(d);
  func(std::move(a));
  func(std::move(b));
  func(std::move(c));
  func(std::move(d));

}

此处,Type专门化中的func_op<>模板参数表示常规值类型。然后,我们提供模板operator(),以提供基于参考的通用实现。

T中的func<T>被转换为&#39;一般值类型&#39;通过std::decay_t - 它具有剥离所有const,volatile和引用修饰符并使我们留下原始类型(例如int)的效果。

如果我们希望为(例如)const int refs提供特殊处理,我们可以进一步专门化或重载operator()。