Проблема в том, что 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;
...
};
}
Опять-таки, надумано, но компилятор не может знать заранее при синтаксическом анализе шаблона, которыйтакой специализации не будет, пока вы на самом деле не создадите экземпляр шаблона с определенным типом.