Шаблоны C ++: Возвращение списка :: итератор - PullRequest
3 голосов
/ 11 апреля 2011

Как я могу заставить работать следующий код? Во время компиляции я получаю сообщение о том, что функция searchForResource не имеет типа возврата.

template<class T>
class ResourceManager
{
  private:
    struct ResourceWrapper;
    std::list<ResourceWrapper*> resources_; // This compiles fine

    std::list<ResourceWrapper*>::iterator  // Error occurs here
        searchForResource(const std::string& file);
};

Кроме того, как бы я определил функцию searchForResource?

template<class t>
std::list<typename ResourceManager<T>::ResourceWrapper*>::iterator
    ResourceManager<T>::searchForResource(const std::string& file)
{
    // ...
}

Ответы [ 6 ]

9 голосов
/ 11 апреля 2011

std::list<ResourceWrapper*>::iterator трудно понять компилятору.Добавьте в префикс typename как в реализации, так и в объявлении, чтобы компилятор знал, что это тип.

Примерно так:

typename std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);
5 голосов
/ 11 апреля 2011
template<class T>
class ResourceManager
{
  private:
    struct ResourceWrapper;
    std::list<ResourceWrapper*> resources_;

//      | typename lost here
//      V
    typename std::list<ResourceWrapper*>::iterator
        searchForResource(const std::string& file);
};

template<class T>
//  | typename lost here                    asterisk lost here | 
//  V                                                          V 
typename std::list<typename ResourceManager<T>::ResourceWrapper*>::iterator
    ResourceManager<T>::searchForResource(const std::string& file)
{
   return ...   
}
3 голосов
/ 11 апреля 2011

Я думаю, вам не хватает ключевого слова typename.

2 голосов
/ 11 апреля 2011

Существует практическое правило, позволяющее избежать таких ошибок компиляции.

Всякий раз, когда вы объявляете переменную или функцию , с шаблоном, за которым следует оператор разрешения области действия ::, всегда ставьте ключевое слово typename перед определением. 1009 * Например,

MyNameSpace::MyClass<T> x; // Ok; because template is NOT followed by scope resolution
MyNameSpace::MyClass<T>::MyType x; // Error; MyType can be a variable or a type; so put typename ahead

То же самое применимо и к объявлению функции.

1 голос
/ 11 апреля 2011

Проблема в том, что ResourceWrapper является зависимым именем * (его определение зависит от аргумента типа T), и это делает std::list< ResourceWrapper * > именем зависимого типа.Шаблоны проверяются в два прохода, во время первого прохода проверяется правильность шаблона без фактической замены типа.Теперь, когда вы набираете std::list< ResourceWrapper* >::iterator, компилятор не может заранее знать, что iterator на самом деле является типом, а не статическим атрибутом или членом класса std::list< ResourceWrapper* >, поскольку тип является зависимым, а T еще не подставляется.

Вы должны намекнуть компилятору, чтобы сообщить ему, что iterator действительно является типом, используя ключевое слово typename, как уже упоминалось ранее:

typename std::list< ResourceWrapper* >::iterator

БезВидя остальную часть кода, я не могу сказать, но кажется, что ResourceWrapper не должен быть зависимым типом для T.Если это на самом деле не зависит, вы должны переместить тип за пределы шаблона класса.в этом случае typename больше не потребуется:

struct ResourceWrapper;
template <typename T>
class ResourceManager {
   std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);
...

Поскольку он определен вне шаблона, существует единственное определение для всех возможных экземпляров шаблона ResourceManager, теперь ResourceWrapper больше не зависит от T, а typename больше не требуется (и не правильно).

* Почему зависит ResourceWrapper и как это может повлиять на код.

Причину, по которой ResourceWrapper зависит от типа T, легче понять, если обсудить полное имя: ::ResourceManager<T>::ResourceWrapper.T является частью типа, и поэтому T влияет на фактическое определение ResourceWrapper.Это как-то надуманный пример, в котором вы можете с уверенностью сказать, что если компилятор анализирует этот конкретный шаблон, то он должен знать, что ResourceWrapper является типом, и, таким образом, std::list< ResourceWrapper*>::iterator является типом ... и вотпроблема.Нет особой причины не иметь специализацию шаблона std::list для конкретного экземпляра ResourceManager:

namespace std { // you should in general not add things to the std namespace!
                // but the implementation can
template <>
struct list< ResourceManager<int>::ResourceWrapper > {
   static const int iterator = 5;
...
};
}

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

0 голосов
/ 11 апреля 2011

у вас есть предварительное объявление структуры ResourceWrapper, которое достаточно для строки, которая хорошо компилируется, но вы получаете ошибку, потому что в этот момент компилятору требуется полное объявление типа для структуры ResourceWrapper.(возможно, ваш ответ, этот код на самом деле прекрасно с VS2008)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...