Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ nested templates [duplicate]

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.

like image 548
sold Avatar asked Nov 30 '25 18:11

sold


2 Answers

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.

like image 102
jalf Avatar answered Dec 03 '25 08:12

jalf


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...

like image 43
shoosh Avatar answered Dec 03 '25 09:12

shoosh



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!