C++模板限制

问题描述:

我想知道有什么方法可以对模板类设置限制吗?
指定在模板中替换的每个类型都必须具有特定的祖先(实现某个接口)。C++模板限制

template < class B > //and every B must be a child of abstract C 
class A { 
public: 
    B * obj; 
    int f() { 
     return B::x + this->obj->f(); 
    } 
}; 

像=>在Haskell

func :: (Ord a, Show b) => a -> b -> c 
+1

为什么你认为你需要这个? – fredoverflow 2010-06-17 14:14:07

+0

可能的[特定基类的C++类模板]的副本(http://*.com/questions/2012950/c-class-template-of-specific-baseclass) – SLaks 2010-06-17 14:14:44

+1

sooooo不是初学者的问题:-)。概念实际上颇具争议。 – 2010-06-17 14:33:30

可以use BOOST_STATIC_ASSERT或类似的库断言在模板参数的限制。

例如:

#include <limits> 
#include <boost/static_assert.hpp> 

template <class UnsignedInt> 
class myclass 
{ 
private: 
    BOOST_STATIC_ASSERT((std::numeric_limits<UnsignedInt>::digits >= 16) 
         && std::numeric_limits<UnsignedInt>::is_specialized 
         && std::numeric_limits<UnsignedInt>::is_integer 
         && !std::numeric_limits<UnsignedInt>::is_signed); 
public: 
    /* details here */ 
}; 

编辑:对于你的榜样,你可以写

template < class B > 
class A { 
    BOOST_STATIC_ASSERT(boost::is_base_of<C, B>); 

public: 
    B * obj; 
    int f() { 
     return B::x + this->obj->f(); 
    } 
}; 

你可以使用一个小技巧是这样的(如果你不想使用升压) :

class Base 
    { 
    public: 
     static const int TEMPLATE_REQUIRES_BASE_CLASS = 0; 
    }; 

class Correct : public Base 
    { 
    }; 

class Incorrect 
    { 
    }; 

template <typename T> 
class TMPL 
    { 
    static const int TEMPLATE_REQUIRES_BASE_CLASS = T::TEMPLATE_REQUIRES_BASE_CLASS; 
    T *m_t; 
    }; 

void main() 
{ 
TMPL<Correct> one;  // OK 
TMPL<Incorrect> two; // Will not compile 
} 

第一行将编译。第二个将无法编译,并给了以下错误:

test.cpp 
test.cpp(18) : error C2039: 'TEMPLATE_REQUIRES_BASE_CLASS' : is not a member of 'Incorrect' 
     test.cpp(12) : see declaration of 'Incorrect' 
     test.cpp(25) : see reference to class template instantiation 'TMPL<T>' being compiled 
     with 
     [ 
      T=Incorrect 
     ] 
test.cpp(18) : error C2065: 'TEMPLATE_REQUIRES_BASE_CLASS' : undeclared identifier 
test.cpp(18) : error C2057: expected constant expression 
+0

由于某些未知原因,此代码在g ++ 4.4下不会失败。一般来说,我会说在这种情况下,通常使用枚举: enum {TEMPLATE_REQUIRES_BASE_CLASS = 0}; 这还有一个额外的好处,就是在g ++下没有达到预期的效果。 – iksemyonov 2010-06-17 15:34:14

+0

@Semen,GCC不合格。标准要求数据成员的声明在类被隐式实例化时实例化,并且类内的初始化器是声明的一部分,而不是定义它的定义。然而,该标准略有不清,称“除非静态数据成员本身以需要定义静态数据成员存在的方式使用,否则不会发生静态数据成员的初始化(以及任何关联的副作用)。 “ - 这个规则似乎只适用于一个超类初始化(否则没有意义) – 2010-06-17 16:13:51

+0

@Johannes:谢谢你的解释,我认为当它建好的时候我疯了......但是我猜枚举仍然是使用更简单。 (我只是跟随范德瓦尔德:) – iksemyonov 2010-06-17 16:28:17

C++的未来版本将支持这一本身使用的概念(这并没有使之成为C++ 11)。来解决这个问题

一种方法是在一个虚拟的模板参数使用专业化:

class C {}; 
template <class B, class dummy=void> 
class A; 

template <class B> 
class A<B, typename enable_if<is_base_and_derived<C, B> >::type> 
{ 
    // class definition here 
}; 

struct D : C {}; 

A<D> d;  // fine 
A<int> n; // compile error - undefined class A<B> 

我就把enable_ifis_base_and_derivedhere独立的定义。

+0

谢谢,真棒一段代码 – Andrew 2010-06-17 15:29:26

模板是用C++编写的鸭子。

如果你的类支持模板使用的所有东西,那么它可以用作模板参数,否则它不能。

如果您的模板,你有类似

C *instance; 

void foo(T *t) 
{ 
    instance = t; 
} 

那么你执行T是从C(或至少assignement兼容的指针)

下使用VC10衍生作品static_assert。我刚刚看到这个使用过,并没有真正挖掘static_assert实际上做了什么 - 也许别人可以回答。

#include <type_traits> 

class Base 
{ 

}; 

class Derived : public Base 
{ 

}; 

class SomeRandomClass 
{ 

}; 

template<typename T> 
class A 
{ 
    static_assert(std::tr1::is_base_of<Base, T>::value, "T not derived from Base"); 
}; 



int _tmain(int argc, _TCHAR* argv[]) 
{ 
    argc; argv; 

    // 
    // This will compile 
    A<Derived> a; 

    // 
    // This will throw a compilation error 
    A<SomeRandomClass> b; 

    return 0; 
} 

编译器输出端:

1>d:\temp\aaa\aaa\aaa.cpp(25): error C2338: T not derived from Base 
1>   d:\temp\aaa\aaa\aaa.cpp(41) : see reference to class template instantiation 'A<T>' being compiled 
1>   with 
1>   [ 
1>    T=SomeRandomClass 
1>   ]