sold
sold

Reputation: 2091

Strange VC++ compile error, C2244

Take a look at this peice of code:

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

When I try to compile it using VSTS 2008, I get:

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'

The declaration:

Pointer<Iterator> GetBeginning() const;

is inside the class. BinaryTree indirectly inherits from Collection, and BinaryTreeIterator indirectly inherits from Iterator, both nested classes of their respective containers.

You can easily see that even in the error report, both definition and declaration are identical. Is there really something wrong here?

I found that microsoft released a hotfix: "Certain template code does not compile, and error C2244 occurs after you install Visual Studio 2005 Service Pack 1". However I couldn't find any reference to VSTS 2008.

So first I wanted to check if anybody could spot a real error in the code at a glance, and if it's VS's fault, does anyone know if the above hotfix is the solution and is relevant for 2008 as well.

Upvotes: 2

Views: 2616

Answers (3)

Andre
Andre

Reputation: 94

It will compile if you change it to this:

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

In general, the original code isn't quite right because it implies that GetBeginning() can return any collection, while (I'm assuming) it can only return binary tree collections.

EDIT:

After some digging, it seems that VC++ doesn't handle well injected class names. That is, the original code will compile if you remove from Collection::Iterator in the method declaration:

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

Upvotes: 0

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247989

For those interested, I tried writing a minimal sample reproducing the problem:

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

And yes, I get the error too. I can't see any obvious errors in what we've seen of your code, but then again, just this example has used more nested classes and inheritance than most sane C++ programmers do in a year, so I can't say for sure that your code is or isn't correct.

Moreover, I've had to guess quite a bit to piece this together. (What's atBeginning supposed to be? What are the actual class interfaces?)

But I suspect it'd work better (and be more readable and easier to debug) if you didn't inherit everything from everything else.

Update I tried compiling the above with GCC and Comeau's online compiler, and both accepted it. So it seems like it could be a compiler bug.

Upvotes: 2

shoosh
shoosh

Reputation: 78934

The obvious solution which you probably considered is to just define the function inside the class definition instead of redefining it later.

Also, Putting the iterator type in a typedef like so:

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

seems to fix it. Not sure why, possibly a bug...

Upvotes: 1

Related Questions