C ++模板限制

时间:2010-06-17 14:07:00

标签: c++ templates

我想知道有没有办法对模板类设置限制?
指定模板中替换的每个类型必须具有特定的祖先(实现一些接口)。

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

喜欢=&gt;在haskell

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

5 个答案:

答案 0 :(得分:6)

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_derived here进行了单独定义。

答案 1 :(得分:3)

以下在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>          ]

答案 2 :(得分:2)

您可以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();
    }
};

答案 3 :(得分:2)

你可以使用这样的技巧(如果你不想使用Boost):

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

答案 4 :(得分:1)

模板在C ++中有点类型。

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

如果您的模板中有类似

的内容
C *instance;

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

然后你强制要求T从C派生(或者至少与指针兼容)