【问题标题】:Does it make any sense to specialize a function template with universal reference parameters?使用通用引用参数专门化函数模板是否有意义?
【发布时间】:2016-09-02 10:26:41
【问题描述】:

对于模板函数,我们可以将其特化如下:

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

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

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

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

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

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

由于模板函数可以接受左值和右值,而“特化”函数只能接受右值。

我还应该用左值引用定义一个“专业化”吗?

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

而这两个“特化”使原始模板函数的特化?或者有专门的专业有什么意义吗?

【问题讨论】:

  • 你是说你想为一个 int 参数的所有表达式专门化 func,即 int、int&、int&&、const int& ?
  • 你能不能再高一点,在更高的层次上描述你想要解决的问题?
  • 对这些特定示例进行专门化并没有多大意义,而不仅仅是完全的重载
  • @RichardHodges 我想将它专门用于int&amp;int&amp;&amp;。为了您的提醒,也许还有const int&amp;。我认为int 是不考虑的,因为在功能void func(T &amp;&amp;t)t 永远不能到int

标签: c++ templates c++11


【解决方案1】:

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

函数有重载。使用那些。

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

在这种情况下,它可能很简单:

template <typename T>
void func(T&&){}
void func(int){}

或者:

template<class T>struct tag_t{};
template<class T>constexpr tag_t<T>tag{};
namespace 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));
}

【讨论】:

    【解决方案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));
    
    }
    

    这里,func_op&lt;&gt; 的特化中的Type 模板参数代表通用值类型。然后我们提供一个模板化的operator() 以提供基于通用引用的实现。

    func&lt;T&gt; 中的 Tstd::decay_t 转换为“通用值类型”——其效果是剥离所有 const、volatile 和引用修饰符,并为我们留下原始类型(例如 int) .

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-12
      • 1970-01-01
      相关资源
      最近更新 更多