如何确保模板参数是所需类型的子类型?

时间:2011-08-11 02:50:23

标签: c++ templates

我有一个模板类,我想要做的是以下

  1. 确保仅在传递的模板参数是所需类型的子类型时才实例化对象
  2. 预先向代码用户传达模板参数必须满足的内容
  3. (1)在某种意义上是自动处理的,如果传递的模板参数不支持该类使用的某些功能,则代码将无法编译。但是这个错误可能会很晚才被发现。我希望检查尽可能早。我还想要实现的是,传递的模板参数必须从我提供的基类型派生出来,这应该是显而易见的。

    首先,这是误入歧途吗?如果不是我该怎么做? (最简单的方法,C ++对我来说还是新手)

    感谢stackoverflow,你真的加快了我的C ++学习速度。

3 个答案:

答案 0 :(得分:42)

鉴于某些完整类型MyBase,如果T不是来自MyBase,则以下内容会产生编译时错误:

#include <boost/type_traits/is_base_of.hpp>
#include <boost/static_assert.hpp>

template<typename T>
class Foo {
    BOOST_STATIC_ASSERT_MSG(
        (boost::is_base_of<MyBase, T>::value),
        "T must be a descendant of MyBase"
    );
    // Foo implementation as normal
};

如果您正在使用带有TR1的C ++ 03编译器,则可以使用std::tr1::is_base_of代替boost::is_base_of;如果您使用的是C ++ 11编译器,则可以使用std::is_base_of代替boost::is_base_ofstatic_assert关键字而不是BOOST_STATIC_ASSERT_MSG宏:

#include <type_traits>

template<typename T>
class Foo {
    static_assert(
        std::is_base_of<MyBase, T>::value, 
        "T must be a descendant of MyBase"
    );
    // Foo implementation as normal
};

N.b。对于私有和模糊派生类型,这将产生 true_type ,因此,如果您真正需要的是将T 视为-a ,则这是不够的MyBase(在大多数情况下)。

文档链接:
BoostStaticAssert
BoostTypeTraits

答案 1 :(得分:4)

从“现代C ++设计”,第2.7章(“在编译时检测可转换性和继承”):您可以使用sizeof技巧:

typedef char Small;
class Big { char dummy[2]; };

Small Test(Base1);
Big Test(...);

const bool isSubclassOfBase1 = sizeof(Test(Derived1())) == sizeof(Small);

它利用了sizeof(...)可以找出表达式求值的类型的事实,并且由于返回值具有不同的大小,==检查的计算结果为true或false。如果Derived1确实是Base1的基础,则选择Small Test(Base1);重载并且isSubclassOfBase1为真。

从此扩展,您可以封装检查并执行静态断言以使其在编译时失败:

#include <boost/static_assert.hpp>

class A {};
class B: public A {};
class C {};

template<class Base, class Derived>
struct SubclassCheck
{
    typedef char Yes;
    class No { char dummy[2]; };

    static Yes Test(Base);
    static No Test(...);
    enum {
        Value = (sizeof(Test(*(Derived*)NULL)) == sizeof(Yes))
    };
};

#define CHECK_DERIVES(b,d)\
    BOOST_STATIC_ASSERT((SubclassCheck<b,d>::Value));

int
main()
{
    CHECK_DERIVES(A, B);
    // CHECK_DERIVES(A, C); // fails
}

您可以使用任何其他静态断言实现,不一定是Boost的。

答案 2 :(得分:0)

是的,这是自动处理的,因为如果参数不支持你用它做的事情,将导致编译错误。手动检查类型是否是另一种类型的子类型只能在运行时完成(AFAIK),这比晚于编译时间。我不知道你迟到检测到的错误是什么意思,编译时间早就得到了。此外,如果每个人都检查了他们的模板参数的类型,那么STL不能使用指针以及基于类的实际迭代器,并且不会那么灵活。

至于让您的用户了解要求,只需在文档中提供。