强制接口的模板

时间:2009-10-11 13:04:44

标签: c++ inheritance templates

是否可以创建一个模板来接受实现某些接口的类型? 例如,我想对模板用户说:只要它实现了Init()Destroy()方法,你就可以在我的容器中存储任何东西。

由于

7 个答案:

答案 0 :(得分:6)

Boost Concept Check library提供概念的C ++ 0x功能的有限子集(预期但不幸地被切断)。您可以通过为所需界面创建concept check class来利用它。

答案 1 :(得分:2)

首先,如果您需要存在Init和Destroy,则意味着模板代码在某处使用它们。这意味着,编译器已经检查了它们的存在,因为如果类型没有这些方法,模板将无法编译。

但是,如果要检查它们,那么一种方法可能是在某些编译时上下文中使用它们的地址,例如

template <class T>
class X
{
private:
    template <unsigned N>
    struct Number {};
    Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
};

struct A
{
    bool Init();
    void Destroy();
};

struct B {};

int main()
{
    X<A>();
    X<B>();
}

使用Comeau,输出为:

"ComeauTest.c", line 7: error: class "B" has no member "Init"
          Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
                            ^
          detected during instantiation of class "X<T> [with T=B]" at line 21

"ComeauTest.c", line 7: error: class "B" has no member "Destroy"
          Number<sizeof(&T::Init) + sizeof(&T::Destroy)> must_define_init_and_destroy();
                                               ^
          detected during instantiation of class "X<T> [with T=B]" at line 21

然而,如果任何一个必需的方法被重载,这会破坏,当然这仍然不会测试这些方法是否具有合适的原型。

也许你期望bool Init(int,int)。您可以使用static_cast来检查确切的签名,但是这可能会对类型造成不必要的限制。例如,那么如果某个类有bool Init(长,长)呢?

无论如何,这种努力似乎只是为了使错误消息更加明显。但是,我非常怀疑在没有任何概念检查的情况下你会得到的任何消息(“在这里使用时没有合适的方法初始化调用T = X”)是那么糟糕。

答案 2 :(得分:1)

不,这是不可能的。

模板替换为一个类型,而不是许多不同的。

考虑创建一个所有可能成员必须继承的基类,并保留所有模板。

你基本上要介绍{+ 3}},这在C ++中是不受支持的。

答案 3 :(得分:0)

目前的标准不可能。我相信有可能通过“概念”假设(?)成为C ++ 0x的标准。

答案 4 :(得分:0)

好吧,我想你可以定义一个在模板参数上调用Init()Destroy()的方法,并以某种方式在调试模式下调用此方法。

或者,您可以定义一个接口,并在模板实现中强制转换为此接口。这也可以在发布模式下禁用。

答案 5 :(得分:0)

是的,你可以。

然而,它非常复杂(高级模板元编程) 整个概念建立在C ++模板中的“替换失败不是错误(SFINAE)”质量的基础上。

从本质上讲,您可以使用 'template <typename T, void (T::*)()>' 之类的模板进行模板,并在向量中使用 <T, T::Init> 进行实例化。除非存在替换,否则将出现替换错误(此处使用SFINAE原则,因为大多数情况下您希望使用构造函数)。

当然,这是简化描述。对不起,我目前无法提供更好的服务,但您可能需要查看this discussion。搜索has_member和is_call_possible。

我希望它有所帮助 奥伦

答案 6 :(得分:0)

实际上,情况正好相反:如果您的模板需要Init()Destroy(),则无法使用具有这两者的任何类型对其进行实例化。

模板在这方面唯一的问题是需求是隐式的(即模板不会在模板中需要的位置编译),而不是显式的(即编译器告诉你在这一点上缺少什么)实例化)。概念是为了解决这个问题,但不久之前它们是taken out of the next standard