【问题标题】:Template specialization restricted by a condition受条件限制的模板特化
【发布时间】:2014-01-12 16:18:33
【问题描述】:

是否可以让编译器根据类型特征在模板规范之间进行选择?例如,考虑比较函数的两种模板实现,一种用于顺序类型(strings、vectors、lists 等),另一种用于整数类型。我们可以为每一类类型只有一个模板特化吗?

template <class SeqT>
class Compare
{
public:
   bool operator()(const SeqT& s1, const SeqT& s2) const
   {
      typename SeqT::const_iterator it1=s1.begin();
      typename SeqT::const_iterator it2=s2.begin();
      while(it1!=s1.end() && it2!=s2.end())
      {
         if(*it1<*it2) return true;
         if(*it2<*it1) return false;
         ++it1; ++it2;
      }
      return it2!=s2.end();
   }
};

template <class IntegerT>
class Compare
{
public:
   bool operator()(IntegerT i1, IntegerT i2) const
   {
      return i1<i2;
   }
};

template <class T, class Cmp = Compare<T> >
class SomeContainer
{
   ...
};

基本上,我正在寻找一种通过对模板参数施加条件来部分特化模板的方法。像第一个 Compare&lt;&gt; 特化应该应用于以下类型:std::basic_string&lt;&gt;std::vector&lt;&gt;std::list&lt;&gt;,第二个应用于以下类型:intunsignedshortchar .这可能吗?

【问题讨论】:

  • 是的。查看 std::enable_if
  • 我首先想到了std::enable_if,但我认为最好添加一个模板参数来指示类型的种类,并且可以从基本类型进行TMP“计算”。然后只需提供专业。
  • 序列是什么意思——你是指任何可以使用for (auto x : y)语法迭代的对象吗?

标签: c++ templates specialization


【解决方案1】:

这是我对另一个问题的回答,但这是您需要的。它使用 SFINAE 仅为测试条件为真的模板参数创建模板特化(例如特定类型的蜜蜂)。

https://stackoverflow.com/a/20898554/2805305

编辑

但是我怎样才能准确地指定第一个比较专业化可以应用于例如std::basic_string 和 std::vector?

您创建一个特征来告诉您 T 是向量还是 basic_string 或列表:

#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <complex>
#include <type_traits>
using namespace std;

template <class T>
struct is_seq : std::false_type {
};

template <class T>
struct is_seq<std::vector<T>> : std::true_type {
};

template <class T>
struct is_seq<std::basic_string<T>> : std::true_type {
};

template <class T>
struct is_seq<std::list<T>> : std::true_type {
};

template <class T>
using enable_if_seq_type = typename std::enable_if<is_seq<T>::value>::type;

template <class T>
using enable_if_integral_type = typename std::enable_if<std::is_integral<T>::value>::type;


template <class T, class Enable = void>
class Compare; // <--------  define if you want a Compare for any type that doesn't match any specialization

template <class T>
class Compare<T, enable_if_seq_type<T>> { // specialization for T a vector, string or list
    public:
        void foo() {
            cout << "vector, string and list specialization" << endl;
        }
};

template <class T>
class Compare<T, enable_if_integral_type<T>> { // specialization for T an integral type
    public:
        void foo() {
            cout << "integral specialization" << endl;
        }
};


int main() {
    cout << std::boolalpha;

    cout << is_seq<int>::value << endl; // false
    cout << is_seq<std::vector<int>>::value << endl; // true

    Compare<int> c1; // uses second specialization
    c1.foo(); // output "integral specialization" 

    Compare<std::vector<int>> c2; // uses first specialization
    c2.foo(); // output "vector, string and list specialization"

    //Compare<std::complex<int>> c3;
    // compile error if you just declare and not define the generic Compare.
    // If you define the generic Compare, this will compile and it will use
    // that definition

    return 0;
}

http://ideone.com/JUbwla

如果您希望能够为任何其他类型实例化类 Compare,则定义第一个(通用)Compare 声明。

【讨论】:

  • 谢谢。但是我怎样才能准确地指定第一个比较专业化可以应用于例如std::basic_string 和 std::vector?另外,我不需要编译为fail,而是编译器在类型参数匹配某些条件时选择 适当的模板。所以,就像上面的例子一样,如果 SomeContainer<:string> 被实例化,则使用 Compare,如果 SomeContainer 被实例化,则使用 Compare
  • @bolov 上述方法存在问题。简单的问题是 std::vector 具有不寻常的分配器,std::string 具有非默认字符特征等都不起作用。根本问题是,与进行某种鸭式测试相比,维护template 或匹配条件的类型列表通常是一个坏主意。
  • @bolov 感谢您的代码示例!我现在可以更好地理解类型启用器的概念了。
  • @Yakk 关于模板声明中的默认类型,您提出了一个非常重要的观点。使用类型受限的模板特化可能通常是不可接受的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多