奇怪的VC ++编译错误,C2244

时间:2009-09-28 00:19:07

标签: c++ visual-studio-2008 templates compiler-errors

看看这段代码:

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 个答案:

答案 0 :(得分: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的在线编译器编译上面的内容,并且都接受了它。所以它似乎可能是一个编译器错误。

答案 1 :(得分:1)

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

另外,将iterator类型放在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();
}

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

答案 2 :(得分: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 ++似乎无法处理注入良好的类名。也就是说,如果从方法声明中删除Collection :: Iterator,原始代码将被编译:

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>();
}