2011-04-15 41 views
2

注:这是一个后续问题this.强制常见方法名称

我有一组做使用完全不同的数据类型以完全不同的方式完全不同的事情的模板类。然而,他们确实有共同的方法名称。例如,Get()Set(),Resize()等对于所讨论的每个类都是有效的方法。另外,他们以相同的顺序接受参数。这允许通用的非朋友,非成员函数在每个类上工作。一个简单的例子:

template <typename Class, typename Datatype> 
void Insert(const Class<Datatype>& Object, const std::size_t Index, const Datatype Value) 
{ 
    Object.Resize(Object.Size() + 1); 
    for (std::size_t CurrentIndex = Object.Size() - 1; CurrentIndex > Index; CurrentIndex--) 
    { 
     Object.Set(CurrentIndex, Object.Get(CurrentIndex - 1)); 
    } 
    Object.Set(Index, Value); 
} 

现在,我只是凭着自己的记忆正确定义所有适当的方法。有没有办法让编译器强制执行适当方法的定义?如果没有,有没有更好的方法来做到这一点?

回答

2

编译器将强制执行正确的接口,因为未能将任何调用编译为不存在的函数;也许问题在于错误信息太神秘了?

您可以定义一个基类,它声明所需的接口为非虚拟函数。基类函数没有定义(除非在默认实现中有一个可选函数)。

然后,如果模板参数从该基类派生,不执行所需要的功能将导致连接错误(由于试图调用基类的功能,这是没有定义)。与典型的模板相关的编译错误相比,这很可能会更容易诊断。

你可以走一步,包括一个编译时检查模板参数从基类派生;我将把它作为读者的练习。或者,只记录基类的用途可能会更好,而不管用户是否使用它。

+1

对于第一部分来说,+1但是我认为检查模板参数是否来自特定的基础使得代码更难使用。至少我不希望模板代码行为如此。 – pmr 2011-04-15 14:13:15

+0

@pmr:是的,我不确定这是不是一个好主意。如果你想要更好的诊断,“从这个类派生出来”的评论可能比执行一些不是必须的东西要好。 – 2011-04-15 14:17:05

+0

那么,例如,像这样的东西? http://snipt.org/xgglj – Maxpm 2011-04-15 14:34:27

0

您可以使用一个接口。

看到这个问题:How do you declare an interface in C++?

+0

“接口”(或抽象基类)不一定是他想要的。他需要一组特定的函数名称,但是这些函数的返回类型和其他方面可能并不需要完全相同。 – 2011-04-15 13:51:25

+0

我不能使用纯粹的虚拟方法,因为派生类将使用任意返回类型,模板化虚拟方法显然会让鼻恶魔跟随我。 – Maxpm 2011-04-15 13:52:23

3

编译器已经通过拒绝让你实例化的类型,不提供必要的方法模板强制执行这些方法的定义。

不幸的是,编译器的不可实例模板错误信息往往很难破译。

您可以在注释中记录类型要求。看看C++标准是如何定义类型需求的,比如Assignable,CopyConstructible,EqualityComparable,LessThanComparable和标准容器中类型的需求。

+0

当然,这会导致“找不到方法”错误,但有没有更清晰的方法? – Maxpm 2011-04-15 13:55:05

+0

@Maxpm什么是更清洁的方式? – 2011-04-15 14:00:53

+0

@Vjo嗯,我不知道。这就是我问的原因。 :P – Maxpm 2011-04-15 14:02:24

3

你所寻找的被称为“concepts”,并曾经是C++ 0x中的特征,但在新标准得到了下降。

有对C++ 03在那里一些实现,但它们很难使用,可能是不值得的麻烦。例如Boost Concept Checking

GCC也有--enable-概念检查选项,虽然我不完全知道如何与用户代码工作。