2015-11-03 4 views
1

UPDATE 2Возможная ошибка компилятора? автоматический вычет не представляется возможным при вызове шаблонного метода с указателем, извлеченным из шаблонной статической функции члена

Почему это ознаменовало дубликат? Where and why do I have to put the “template” and “typename” keywords? не отвечает на этот вопрос. Описанное здесь поведение нигде не упоминается (вы не найдете ни одного замечания о ожидаемом поведении auto).

Это не дубликат, тем более, что в разных компиляторах существует противоречивое поведение.


UPDATE

Многое, как GCC, лязг также не компилировать:

17 : error: expected expression 
return p->is<true>(); 
^ 

Однако на MSVC код с auto обнаружения успешно компиляции.

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


Live example

Рассмотрим следующий класс:

struct A { 
    template<bool> 
    bool is() const { 
     return true; 
    } 

    template<bool> 
    static A* get() { 
     static A a; 
     return &a; 
    } 
}; 

Если шаблонной функции, такие как

template<bool cond> 
bool foo() { 
    auto p = A::get<cond>(); 
    return p->is<true>(); 
} 

пытается вызвать A::is<bool>, она с треском проваливается:

main.cpp: In function 'bool foo()': 
main.cpp:17:24: error: expected primary-expression before ')' token 
    return p->is<true>(); 
         ^
main.cpp: In instantiation of 'bool foo() [with bool cond = true]': 
main.cpp:21:22: required from here 
main.cpp:17:17: error: invalid operands of types '<unresolved overloaded function type>' and 'bool' to binary 'operator<' 
    return p->is<true>(); 
       ^

однако, если только заменить auto с явным типом (A*):

template<bool cond> 
bool foo() { 
    A* p = A::get<cond>(); 
    return p->is<true>(); 
} 

он работает.

В чем причина этого?

+3

... и вы не должны утверждать, что обнаружили ошибку компилятора, если у вас нет действительно веских оснований говорить об этом. – Petr

+0

@Petr Почему? Ошибки компилятора действительно не так уж необычны. Я встречал их бесчисленное множество. Это подозрительное поведение, которое несовместимо для разных компиляторов, поэтому я не понимаю, почему я должен иметь действительно хорошую причину, просто чтобы узнать, может ли это быть ошибкой компилятора. –

+2

И я думаю, вы знаете, что гораздо более распространенными являются люди, утверждающие, что они обнаружили ошибку компилятора, в то время как на самом деле они просто не понимали стандарт должным образом. Более того, это просто признак вежливости, чтобы не сказать, что кто-то другой ошибается, если вы абсолютно не уверены. См. [Этот раздел] (http://www.catb.org/esr/faqs/smart-questions.html#idp59344752) «Как задавать вопросы умным путем» Э.С. Раймонд. – Petr

ответ

9

Вам нужно написать

return p->template is<true>(); 

, потому что компилятор не изначально не знает, что is шаблон.


Некоторые более глубокие объяснения. С

A* p = A::get<cond>(); 
return p->is<true>(); 

компилятор знает, даже если он разбор кода, который p имеет типа A* и, следовательно, он видит, что p->is шаблон.

С

auto p = A::get<cond>(); 
return p->is<true>(); 

компилятор изначально не знать, какой тип p будет. Он будет знать это только после того, как он создал экземпляр A::get<cond>, и это произойдет только при создании экземпляра foo. Поэтому он не знает, что p->is является шаблоном. (И это может легко быть не шаблон вы специализировались версия A, скажем, true параметр шаблона.)

Дальнейшее чтение: Where and why do I have to put the "template" and "typename" keywords?


Цитата из стандарта [14.2.4]:

После названия специалиста по шаблону участника появляется после. или -> в постфиксном выражении или после спецификатора вложенного имени в идентификаторе с квалификацией, а выражение объекта postfix-expression - , зависящее от типа или вложенное имя-спецификатор в идентификаторе квалифицированного идентификатора зависимому типу, но имя не является членом текущего экземпляра (14.6.2.1), имя шаблона члена должно иметь префикс шаблона ключевых слов. В противном случае предполагается, что имя имеет имя без шаблона.

Я думаю, это ясно объясняет, что наблюдаемое является правильным поведением. Без auto тип p не зависит от типа. С auto становится зависимым от типа.

+1

Почему? почему он знает, что 'is' является шаблоном при работе с явным типом по сравнению с' auto'? Я не прошу о способах выполнения этой работы, я ищу причины (желательно цитаты из стандарта). –

+0

@Avidanborisov, вы видели редактирование (которое добавило часть после горизонтального правила)? – Petr

+1

У меня есть, но он не отвечает на вопрос. Ваше предположение, почему компилятор не обнаруживает 'is', является шаблоном, хорошо, но я ищу определенные ответы: это фактическое * ожидаемое * стандартно-совместимое поведение? –