Странная ошибка компиляции 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>();
}