Странная ошибка компиляции 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, оба вложенных класса их соответствующих контейнеров.

Вы можете легко увидеть, что даже в отчете об ошибке и определение, и объявление идентичны. Здесь действительно что-то не так?

Я обнаружил, что Microsoft выпустила исправление: "Определенный код шаблона не компилируется, и ошибка C2244 возникает после установки Visual Studio 2005 с пакетом обновления 1 (SP1)". Однако я не смог найти никаких ссылок на VSTS 2008.

Итак, сначала я хотел проверить, может ли кто-нибудь сразу увидеть настоящую ошибку в коде, и если это вина VS, кто-нибудь знает, является ли указанное выше исправление решением и актуально также для 2008 года.

3 ответа

Для тех, кто заинтересован, я попытался написать минимальный образец, воспроизводящий проблему:

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, и оба приняли его. Похоже, это может быть ошибка компилятора.

Очевидное решение, которое вы, вероятно, рассмотрели, состоит в том, чтобы просто определить функцию внутри определения класса, а не переопределять ее позже.

Кроме того, Помещение типа итератора в 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();
}

кажется, это исправить. Не уверен, почему, возможно, ошибка...

Он скомпилируется, если вы измените его на это:

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>();
}
Другие вопросы по тегам