2010-08-04 3 views
1

следующие компилирует в НКУ:ошибки портирование C++ шаблоны из GCC в Visual C++

cvec.hpp:

template <class T> 
class cvec : public deque<T> 
{  
    class deque<T>::iterator Find(T); 
}; 

cvec.cpp:

template <class T> 
class deque<T>::iterator cvec<T>::Find(T element) 
{ 

} 

В Visual C++, получаем:

ошибка C2242 "typedef name не может следовать классу/структуре/объединению.

Я изменил «класс» в файле заголовка на «typename», но получил ошибку C3860 - список аргументов шаблона должен перечислять параметры в порядке, используемом в списке параметров шаблона. В этом случае есть только один параметр: T. Если компилятор не запутался в Find (T element)?

+1

Какая версия Visual C++? –

+0

Visual Studio 2008 – Naish44

+1

'class' и' typename' не являются взаимозаменяемыми в этом контексте. 'class' там не является законным. – jalf

ответ

0

Это работает для меня в 2010 году:

#include <deque> 

template <class T> 
class cvec : public std::deque<T> 
{  
public: 
    typedef typename std::deque<T>::iterator iterator; 
    iterator Find(T element); 
}; 

template <class T> 
typename cvec<T>::iterator cvec<T>::Find(T element) 
{ 
    return std::deque<T>::iterator(); 
} 

using namespace std; 

int main() 
{ 
    cvec<int> c; 
    c.Find(1); 

    return 0; 
} 
+0

Работает также в VS2008 – Praetorian

+0

. Работает также с VS2005. – Gangadhar

+0

Отличный, проверенный это с опубликованным кодом в 2008 году. Не думал о typedef'ing итератора, чем использование этого имеет возвращаемый тип для поиска. – Naish44

4

Что это должно означать в заголовке:

class deque<T>::iterator Find(T); 

Вы не объявляя класс. Ключевое слово typename будет действительным здесь, но class не имеет смысла.

И то же самое верно и в файле .cpp:

template <class T> 
typename deque<T>::iterator cvec<T>::Find(T element) 

является правильным, class нет.

Помимо этого, это действительно похоже на то, что вы пытаетесь сделать, это ужасная идея. std::deque уже имеет функцию find. Оно работает. Верно. Это эффективно. Нет необходимости изобретать его.

Стандартные контейнеры для библиотек также не предназначены для вывода. У них нет виртуальных деструкторов.

Все, что вы достигли (помимо ошибок компиляции), состоит в том, что у вас будет багги, менее эффективный контейнерный класс, который запутает других программистов на С ++, потому что он не использует идиоматический интерфейс.

1

Это должен быть комментарий, но я даю ему ответ, чтобы его можно было форматировать для удобства чтения.

@jalf и @dvl - Как указано в @dvl, ни один из контейнеров std не имеет виртуальных деструкторов. Почему это имеет значение?

Предположим, вы вывели класс «X» из std :: deque.

class X : public std::deque<int> 
{ 
    // whatever ... 
}; 

Теперь скажем, что у вас есть объект «X», на который указывает указатель базы.

std::deque<int> *p = new X; 

и вы удалите его

delete p; 

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

Ваши варианты:
1. Не извлекайте из контейнеров std. Сделайте их членами данных и напишите обертки, чтобы открыть функциональность.
2. Получайте только из std-контейнеров, если производный класс не имеет деструктора и не содержит элементов данных с деструкторами.
3. Если вы выходите из контейнера std, никогда не ссылайтесь на него указателем базы.

После создания класса иногда бывает трудно узнать, как этот класс может быть использован в будущем. По этой причине многие разработчики строго придерживаются варианта «1». Лично я допускаю вывод из контейнера std, если он хорошо документирован и используется с осторожностью.

Смежные вопросы