Strange VC++ compile error, C2244

后端 未结 3 1620
伪装坚强ぢ
伪装坚强ぢ 2020-12-12 01:50

Take a look at this peice of code:

template 
Pointer::Iterator> BinaryTree::GetBegi         


        
相关标签:
3条回答
  • 2020-12-12 02:03

    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.

    0 讨论(0)
  • 2020-12-12 02:06

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

    0 讨论(0)
  • 2020-12-12 02:07

    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>();
    }
    
    0 讨论(0)
提交回复
热议问题