2010-03-16 89 views
12

我有一个基本的模板类,但我想限制专业化的类型为一组类或类型。例如:强制类型的C++模板

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

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

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

这可能吗?如果是这样,怎么做?

谢谢。

+1

我很好奇,什么情况下使用你对禁止模板的一些实例?我无法弄清楚为什么我不喜欢我的代码被重用: -/ – Seb 2010-03-16 14:04:35

+0

“可能会有所不同”是什么意思?可能它们在编译时会有所不同,或者与示例中的不同? – foraidt 2010-03-16 14:12:13

+3

@Seb:模板可能无法正确使用某些类型。它可能不会编译(在这种情况下,一个比任何编译器生成的更干净的错误信息都是可取的),或者它可以编译但不具有所需的语义(在这种情况下,防止编译的方法很好) – jalf 2010-03-16 18:04:39

回答

17

另一个版本是离开它未定义禁种

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 
+2

+1。事实上,我比第一个答案更喜欢这个解决方案。 – paercebal 2010-03-16 22:32:28

+0

@paercebal,谢谢伙计xD – 2010-03-17 07:23:41

+0

不客气。无论如何,自从我上次发表评论以来,你的答案就成为了选定的答案,显然,我不是唯一一个能够看到它的价值的人:--P – paercebal 2010-03-17 14:09:19

1

有各种各样的技巧,允许检查一些事情,这取决于你的标准是什么实例化被允许。在实践中,您应该为Boost的Concept Check等人使用更高级别的库。

8

Yust一个快速的想法,我敢肯定有更好的方法:

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]; 
}; 

这可能是更好的,但是,把脂肪评论过你的代码,以保持用户从错误类型的实例: - )

+0

您击败了我来吧。这里使用的习语称为* type traits *。 – 2010-03-16 14:11:17

+4

是否有另一种方法可以做到这一点,而不会在每个实例中产生char [1]数组的成本?就个人而言,我会使用BOOST_STATIC_ASSERT。 – 2010-03-16 14:13:16

+2

在'char'之前加上'typedef'。 – Ari 2010-03-16 14:31:02

1

林不知道这一点,但您可以添加其他模板专用双 模板

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

template <double> class MyClass 
{}; 

这会为你工作例如,但不适用于一般情况。

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

希望它有帮助。

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; 
}