强制类型的C ++模板

时间:2010-03-16 14:01:20

标签: c++ templates

我有一个基本的模板类,但我想限制一组类或类型的特化类型。 e.g:

template <typename T>
class MyClass
{
.../...
private:
    T* _p;
};

MyClass<std::string> a; // OK
MYCLass<short> b;       // OK
MyClass<double> c;      // not OK

这些只是示例,允许的类型可能会有所不同。

这甚至可能吗?如果是,怎么办?

感谢。

6 个答案:

答案 0 :(得分:17)

另一个版本是为forbidden类型

保留未定义
template<typename T>
struct Allowed; // undefined for bad types!

template<> struct Allowed<std::string> { };
template<> struct Allowed<short> { };

template<typename T>
struct MyClass : private Allowed<T> { 
  // ...
};

MyClass<double> m; // nono

答案 1 :(得分:8)

我很快就会想到,我确信有更好的方法:

template <typename T> struct protector {
static const int result = 1;
};

template <> struct protector<double> {
static const int result = -1;
};

template <typename T> 
class MyClass
{
   private:
     char isfine[protector<T>::result];
};

然而,对您的代码进行粗略评论以防止用户使用错误的类型进行实例化可能会更好: - )

答案 2 :(得分:6)

答案 3 :(得分:2)

通常,不必限制可以实例化哪些类型的模板。模板可以与给定的类型进行编译(并且可以正常工作),或者不是(并且在程序员的帮助下不会产生编译器错误)。


如果您需要加入限制,通常这些类型有一些共同点,可以通过某些已经可用的类型特征(标准库,boost::type_traits)来描述,或者您可以创建一个新的类型特征它们。

例如,这是一个只允许整数类型的模板类,使用std::numeric_limits来检查它(如果你编写自己的数字类型,你可以专门设置它,这样它也适用于你的新整数类型) 。 static_assert仅限C ++ 0x,如果不可用则使用BOOST_STATIC_ASSERT或其他技巧。

#include <limits>
#include <string>

template <class T>
class X
{
    static_assert(std::numeric_limits<T>::is_integer, "X can be only instantiated with integer types");
    //...
};

int main()
{
    X<int> xi;
    X<char> xc;
    //X<double> xd;
    //X<std::string> xs;
}

如果你只打算支持一些没有任何共同点的任意类型(从你的假设例子中可以明显看出),一种方法是使用类型列表。再次提升可能会使任务变得更容易,但是这里你可以自己动手(这只是中途,需要额外的工作来宣布更好的类型列表)。

struct no_type {};

template <class T, class U = no_type>
struct t_list
{
    typedef T head;
    typedef U tail;
};

//trait to check if two types are identical
template <class T, class U>
struct is_same
{
    static const bool value = false;
};

template <class T>
struct is_same<T, T>
{
    static const bool value = true;
};

//compile-time recursion to check if T matches any type in list L
template <class T, class L>
struct in_type_list
{
    static const bool value =
        is_same<T, typename L::head>::value || in_type_list<T, typename L::tail>::value;
};

//terminates recursion
template <class T>
struct in_type_list<T, no_type>
{
    static const bool value = false;
};

template <class T>
class X
{
    typedef t_list<double, t_list<int, t_list<char> > > allowed_types; //double, int, char

    //poor man's static_assert
    typedef int check_type [in_type_list<T, allowed_types>::value ? 1 : -1];
    //...
};

int main()
{
    X<char> xc;
    X<int> xi;
    X<double> xd;
    //X<float> xf;
}

答案 4 :(得分:1)

有各种技巧可以检查某些内容,具体取决于您允许或不允许实例化的标准。在实践中,你应该为Boost的概念检查使用更高的杠杆库。

答案 5 :(得分:1)

我不确定这一点,但您可以为double添加另一个模板专门化 模板

class MyClass
{
.../...
private:
    T* _p;
};

template <double> class MyClass
{};

这适用于您的示例,但不适用于一般情况。

通常,我会添加一个编译断言来检查不需要的类型。

希望它有所帮助。