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