Я столкнулся с этой проблемой в каком-то реальном коде C ++ 11, но я свел ее к следующему:
template<int i> struct Dummy {};
template<typename T>
struct Foo {
template<int i> static constexpr int bar() { return i; }
template<int i>
static auto working() -> Dummy<bar<i>()>;
template<int i>
static auto also_working() -> Dummy<Foo<T>::template bar<i>()>;
template<int i>
static Dummy<Foo<T>::template bar<i>()> not_working();
};
template<typename T> template<int i>
auto Foo<T>::working() -> Dummy<bar<i>()> {
return Dummy<bar<i>()>{};
}
template<typename T> template<int i>
auto Foo<T>::also_working() -> Dummy<Foo<T>::template bar<i>()> {
return Dummy<bar<i>()>{};
}
template<typename T> template<int i>
Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
return Dummy<bar<i>()>{};
}
Я пытался создать внеочередное определение функция-член шаблона класса шаблона, где сигнатура функции включала вызов другой функции-члена шаблона и начиналась с чего-то вроде функции not_working()
. Проблема заключалась в том, что определение не соответствовало декларации.
Clang сказал:
clang++ -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -std=c++11 -c -o out_of_line.o out_of_line.cc
out_of_line.cc:28:42: error: out-of-line definition of 'not_working' does not match any declaration in 'Foo<T>'
Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
^~~~~~~~~~~
GCC сказал:
g++ -Wall -Wextra -pedantic -std=c++11 -c -o out_of_line.o out_of_line.cc
out_of_line.cc:28:34: error: prototype for ‘Dummy<bar<i>()> Foo<T>::not_working()’ does not match any in class ‘Foo<T>’
Dummy<Foo<T>::template bar<i>()> Foo<T>::not_working() {
^~~~~~
out_of_line.cc:14:43: error: candidate is: template<class T> template<int i> static Dummy<Foo<T>::bar<i>()> Foo<T>::not_working()
static Dummy<Foo<T>::template bar<i>()> not_working();
^~~~~~~~~~~
Методом проб и ошибок я обнаружил, что используя конечный тип возврата, я могу получить определение, соответствующее объявлению, что приводит к функция also_working()
. Оказавшись там, я понял, что из-за изменения области видимости в конечном типе возврата я мог отказаться от некоторой квалификации имени, получив гораздо более красивую функцию working()
.
Теперь мне интересно, почему функция not_working()
не работает, то есть почему ее определение не совпадает с ее объявлением (я мог бы просто остаться в неведении относительно решения, которое я нашел, но я, скорее всего, столкнусь с большим количеством такого рода проблемы, и я не хочу тратить больше времени, используя метод проб и ошибок); лежит ли ошибка в компиляторах или в моем коде. Я прочитал 14.6 Разрешение имен [temp.res] , но я не уверен, какие правила применимы для этого случая.
Пояснение вопроса : Учитывая правила в стандарте C ++ 11:
not_working()
соответствовать объявлению?