2012-05-29 1 views
0

рассмотрим следующий код:г ++, вытекающие из класса с параметром шаблона

template<class T> 
class Base { 
    public: 
    void doSomething(){} 
}; 

template<class T> 
class Derived : public Base<T> { 
    public: 
    void doMore() { 
     doSomething(); //Affected line 
    } 
}; 

В строке комментировал с «затрагиваемой линии» г ++ (4.7) говорит:

test.cc:11:16: error: there are no arguments to ‘doSomething’ that depend on a template parameter, so a declaration of ‘doSomething’ must be available [-fpermissive] 

Теперь я задаюсь вопросом:

  • Если параметр шаблона T не существует, эта ошибка не будет возникать. В чем разница?
  • g ++, очевидно, способен решить эту проблему (если я добавлю -fpermissive, он компилируется отлично). Я предполагаю, что g ++ пытается сделать для меня лучший опыт работы как «пользователь» (программист). Каковы преимущества для меня, когда g ++ не принимает этот код?

Спасибо! Nathan

+4

Изменить на 'this-> doSomething()' (или 'Base :: doSomething()'), так как 'doSomething()' зависит от типа 'T'. – hmjd

+0

type 'this-> doSomething();' –

+0

@hmjd: Это интересно .. можете ли вы дать краткое описание того, как добавление 'this->' помогает? – Asha

ответ

1

Эта публикация находится в wiki-странице GCC Verbose Diagnostics.

Каковы преимущества для меня, когда g ++ не принимает этот код?

Он соответствует стандарту и согласуется с другими компиляторами, гарантируя, что ваш код портативен и правилен.

+0

ОК, он соответствует стандарту. Но я должен сказать, что меня раздражает то, что стандарт заставляет меня писать «this-> doSomething()» или использовать «-fmpermissive», и я не понимаю, почему стандарт не может быть «лучше». – Nathan

+1

Если вы специализируетесь на 'Base ', так что 'Base :: doSomething' является членом данных, а не является функцией-членом, тогда было бы недействительно создавать экземпляр' Derived :: doMore', потому что он попытался бы «вызвать» данных. Таким образом, тип имен в базовом классе, или даже они вообще существуют, не могут быть известны до момента инстанцирования, поэтому в базовом классе не возникает смысла до создания экземпляра. Чтобы сообщить компилятору, что имя может появиться из базового класса и ждать, пока экземпляр не выполнит поиск, вы должны определить имя или использовать 'this->', иначе поиск не сможет его найти. –

+1

... альтернатива будет заключаться в том, что компилятор иногда может найти его во время определения, а затем «отмените» его, если он отсутствует во время создания, что было бы непоследовательным и еще более запутанным. Если вы хотите непоследовательность «иногда работает таким образом, иногда работает так», тогда попробуйте PHP ;-) Стандартные _attempts_, чтобы дать единый, однозначный набор правил о том, как скомпилированы шаблоны, и одним из последствий является то, что в шаблонах неквалифицированное имя lookup никогда не смотрит в зависимые базовые классы. –

2

Если вы не добавили this или Base<T>, вы пишете код, который не соответствует стандарту - GCC хочет, чтобы вы этого не делали. Смотрите также запись Изменений для GCC 4.7:

G ++ теперь корректно реализует правила подстановки двухфазных такие, что неквалифицированное имя, используемое в шаблоне, должны иметь соответствующую декларацию, найденные либо в объеме в точке определения шаблон или зависящий от аргументов поиск в момент создания экземпляра. В результате код, который опирается на второй неквалифицированный поиск в момент инстанцирования для поиска функций, объявленных после шаблона или в зависимых базах, будет отклонен. Компилятор предложит способы исправления затронутого кода, а использование флага -fpermissive компилятора позволит компиляции кода с предупреждением.

template <class T> 
void f() { g(T()); } // error, g(int) not found by argument-dependent lookup 
void g(int) { } // fix by moving this declaration before the declaration of f 

template <class T> 
struct A: T { 
    // error, B::g(B) not found by argument-dependent lookup 
    void f() { g(T()); } // fix by using this->g or A::g 
}; 

struct B { void g(B); }; 

int main() 
{ 
    f<int>(); 
    A<B>().f(); 
} 

(здесь: http://gcc.gnu.org/gcc-4.7/changes.html).

+0

GCC отклонил пример OP с _at наименьшим 4.1, что изменение в 4.7 не связано с поиском имен в зависимых базах. –