2009-09-28 169 views
2

看看这个peice的代码:奇怪的VC++编译错误,C2244

template <typename K,typename T> 
Pointer<typename Collection<T>::Iterator> BinaryTree<K,T>::GetBeginning() const 
{ 
    return new BinaryTreeIterator(this,BinaryTreeIterator::Position::atBeginning); 
} 

当我尝试使用VSTS 2008年编译它,我得到:

error C2244: 'BinaryTree<K,T>::GetBeginning' : unable to match function definition to an existing declaration 
see declaration of 'BinaryTree<K,T>::GetBeginning' 
2>  definition 
2>  'Pointer<Collection<T>::Iterator> BinaryTree<K,T>::GetBeginning(void) const' 
2>  existing declarations 
2>  'Pointer<Collection<T>::Iterator> BinaryTree<K,T>::GetBeginning(void) const' 

声明:

Pointer<Iterator> GetBeginning() const; 

是在类中。 BinaryTree从Collection间接继承,而BinaryTreeIterator间接从Iterator继承,它们都是各自容器的嵌套类。

即使在错误报告中,您也可以很容易地看到定义和声明是相同的。这里真的有问题吗?

我发现微软发布了hotfix:“某些模板代码无法编译,安装Visual Studio 2005 Service Pack 1后出现错误C2244”。但我找不到任何对VSTS 2008的参考。

所以首先我想检查是否有人能够在代码中发现一个真正的错误一目了然,如果它的VS的错,有没有人知道如果上述修补程序是该解决方案也适用于2008年。

+3

没有真正的问题有关,但你应该让你的心是否你在写C++或Java的。这看起来像某人天真地从Java移植了函数,而对实际语言差异没有考虑。痛苦的... – jalf 2009-09-28 00:41:27

+0

你试过改变声明指针 :: Iterator> GetBeginning()const? (只是一个想法) – 2009-09-28 00:46:50

+0

@Andrew:改变它如何? – sold 2009-09-28 00:55:30

回答

2

对于那些有兴趣,我试着写一个最小的样品重现问题:

template <typename T> 
struct Pointer {}; 

template <typename T> 
struct Collection { 
    struct Iterator {}; 
}; 

template <typename K,typename T> 
struct BinaryTree : Collection<T>{ 
    Pointer<typename Collection<T>::Iterator> GetBeginning() const; 

    struct BinaryTreeIterator : Collection<T>::Iterator { 
     template <typename X> 
     BinaryTreeIterator(BinaryTreeIterator*, X) {} 
     struct Position { 
      static int atBeginning() { return 0; } 
     }; 
    }; 
}; 

template <typename K,typename T> 
Pointer<typename Collection<T>::Iterator> BinaryTree<K,T>::GetBeginning() const 
{ 
    return Pointer<typename Collection<T>::Iterator>(); 
} 

int main(){ 
    BinaryTree<int, float> bt; 
    bt.GetBeginning(); 
} 

是的,我得到的错误了。在我们看到的代码中看不到任何明显的错误,但是再一次,这个例子使用了比大多数理智的C++程序员在一年中所做的更多的嵌套类和继承,所以我不能肯定地说你的代码是或不是正确的。

此外,我不得不猜测相当多的一部分。 (什么是起始应该是什么?什么是实际的类接口?)

但我怀疑它会更好地工作(并且更可读和更容易调试),如果你没有继承一切从其他一切。

更新 我试着用GCC和Comeau的在线编译器编译上面的代码,并且都接受了它。所以它似乎可能是一个编译器错误。

+0

继承的两个实例比大多数理智的C++程序员在一年中做的更多吗?不太可能。 – shoosh 2009-09-28 00:51:46

+0

感谢您提供复制。希望它能帮助别人得到线索。至于继承方案,这段代码是不会使用stl“flat”容器风格的。除此之外,我不知道“一切都从一切继承”。继承树似乎对我来说自然而直观。 – sold 2009-09-28 00:54:22

+2

我不认为我的例子是一个准确的,我不得不在猜测类的实现过多。你应该真的提供你自己的实际代码。如果你使用STL风格,并且有意或无意,你的代码将更具可读性。如果我在火车前跳投,那么我是否故意这样做会是非常愚蠢的想法。 – jalf 2009-09-28 01:00:38

1

您可能考虑的显而易见的解决方案是在类定义中定义函数,而不是稍后重新定义它。

而且,把迭代器类型在typedef像这样:

template <typename T> 
struct Pointer {}; 

template <typename T> 
struct Collection { 
    struct Iterator {}; 
}; 

template <typename K,typename T> 
struct BinaryTree : Collection<T>{ 
    typedef typename Collection<T>::Iterator Iter; 
    Pointer<Iter> GetBeginning() const; 

    struct BinaryTreeIterator : Collection<T>::Iterator { 
    }; 
}; 

template <typename K,typename T> 
Pointer<typename BinaryTree<K,T>::Iter> BinaryTree<K,T>::GetBeginning() const 
{ 
    return new BinaryTreeIterator(this,BinaryTreeIterator::Position::atBeginning); 
} 

int main(){ 
    BinaryTree<int, float> bt; 
    bt.GetBeginning(); 
} 

似乎解决它。 不知道为什么,可能是一个错误......

+0

谢谢。说实话,我没有尝试过。我习惯于将实现中的声明与模板分开。是的,它确实解决了这个问题。我希望能够分开dec和def,因为这个错误也为班上的其他人重演,并且仍然不明白为什么它不起作用。如果没有其他事情出现,我想我必须这样做。谢谢 :) – sold 2009-09-28 01:12:50

0

如果改成这样它会编译:

template <typename K,typename T> 
struct BinaryTree : Collection<T> { 
    Pointer<typename BinaryTree<K,T>::Iterator> GetBeginning() const; 

}; 

template <typename K,typename T> 
Pointer<typename BinaryTree<K,T>::Iterator> BinaryTree<K,T>::GetBeginning() const 
{ 
    return Pointer<BinaryTree<K,T>::Iterator>(); 
} 

一般情况下,原来的代码是不完全正确,因为这意味着GetBeginning()可以返回任何集合,而(我假设)它只能返回二叉树集合。

编辑:

一些挖后,似乎VC++没有处理好注入的类名。也就是说,如果从收藏::迭代器在方法声明中删除原始代码编译:

template <typename K, typename T> 
struct BinaryTree : Collection<T> { 
    Pointer<typename Collection::Iterator> GetBeginning() const; 

}; 

template <typename K, typename T> 
Pointer<typename Collection<T>::Iterator> BinaryTree<K,T>::GetBeginning() const 
{ 
    return Pointer<Collection<T>::Iterator>(); 
}