我希望这段代码成为可能。
template<typename K, typename T, typename Comparer>
class AVLTree
{
...
void foo() {
...
int res = Comparer::compare(key1, key2);
...
}
...
};
具体来说,我想强制Comparer类具有static int compare(K key1, K key2)
函数。我正在考虑使用派生,但找不到任何可以使用模板的想法。
谢谢。
答案 0 :(得分:4)
你有没有尝试过:
int res = Comparer::compare(key1, key2);
在C ++中,可以通过两种方式调用静态函数:
object.static_method(); // use dot operator
classname::static_method(); // use scope resolution operator
答案 1 :(得分:4)
你做不到。但是如果使用该函数并且Comparer没有它,那么编译将失败,这或多或少是您想要发生的。是的,就像其他人指出的那样,你想把静态称为静态。
答案 2 :(得分:2)
迈克尔already mentioned,如果Comparer
没有所需的成员函数,则无法编译。
如果您更担心简明的错误消息,请使用类似this的内容来检测该类是否具有必需的成员函数,并将其与Boost.StaticAssert之类的内容结合使用:
template<typename K, typename T, typename Comparer>
class AVLTree
{
BOOST_STATIC_ASSERT(HasCompareMethod<Comparer>::has);
//...
};
答案 3 :(得分:1)
它必须是Comparer::Compare
,对吧? (因为你在类型上调用静态函数)。
您的Comparer类必须定义如下:
template<typename K>
class Comparer
{
public:
static bool Compare(K key, K key)
{
return true;
}
};
答案 4 :(得分:1)
我理解,如果模板参数不符合模板主体的要求,您正在寻找更好的错误消息。该语言没有内置的特殊机制,但人们使用库来近似它。见Boost Concept Check
答案 5 :(得分:1)
对此进行编译时断言的松散方法是获取Comparer :: compare的地址并将其分配给声明为int(K,K)* func的变量。
如果它是一个静态函数,该赋值将起作用,但如果它是一个成员函数则不起作用。
我只是贡献了这一点,但我会采用使用提升习语的方法,因为这是手工卷制的,可以这么说。
答案 6 :(得分:1)
这是一种更惯用和通用的方法:
template<typename K, typename T>
class AVLTree
{
...
template <typename Comparer>
void foo(Comparer cmp) {
...
int res = cmp(key1, key2);
...
}
...
};
Comparer不应该是定义静态Compare
方法的类型。它应该是一个可以用函数调用语法调用的类型。这允许您使用函数对象的函数指针,它允许您重用已在标准库中定义的比较器,或几乎任何其他非平凡的C ++应用程序。它允许您在使用lambdas时将它们添加到C ++ 0x中。
强迫Comparer
按预期行事?第int res = cmp(key1, key2);
行已经确保了这一点。如果您尝试传递无法以这种方式调用的类型,则会出现编译错误。
原始代码中的情况也是如此。如果传递的类型没有静态Compare
方法,则会出现编译错误。所以你的原始代码已经解决了这个问题。
答案 7 :(得分:0)
如前所述,您无法强制比较拥有静态成员compare
。如果比较器没有实现它,则只会出现编译器错误。
如果您像这样实施AVLTree
,将Comparer
声明为模板模板参数会更优雅:
template <typename K>
class DefaultComparer
{
public:
static bool compare(K k1, K k2)
{ return k1 == k2; }
};
template <typename K>
class MyComparer : public DefaultComparer<K>
{
public:
static bool compare(K k1, K k2)
{ return k1 <= k2; }
};
template <typename K>
class InvalidComparer
{
public:
static bool bar(K k1, K k2)
{ return k1 != k2; }
// Doesn't implement compare()
};
// Compare is a template template paramenter with default template argument
// DefaultComparer
template <typename K, template <typename K> class Comparer = DefaultComparer>
class AVLTree
{
K k1, k2;
public:
AVLTree() : k1(0), k2(0) { } // ctor
bool foo();
};
// Definiton of AVLTree::foo()
template <typename K, template <typename K> class Comparer>
bool AVLTree<K, Comparer>::foo()
{
return Comparer<K>::compare(k1, k2);
}
int main(int argc, char *argv[])
{
// Without template template parameters you
// would have to use AVLTree<int, DefaultComparer<int> >
AVLTree<int> avltree;
// instead of AVLTree<int, MyCompare<int> >
AVLTree<int, MyComparer> avltree2;
// Calling foo() will generate a compile error.
// But if you never call avltree3.foo() this will compile!
AVLTree<int, InvalidComparer> avltree3;
avltree.foo(); // calls DefaultComparer::compare
avltree2.foo(); // calls MyComparer::compare
avltree3.foo(); // fails to compile
}