У меня есть код, который не компилируется, и я уменьшил его до следующей минимальной версии:
class Builder
{
public:
Builder()
{}
auto foo(int) -> Builder &
{
return *this;
}
template<typename T>
auto bar() -> Builder &
{
return *this;
}
};
template<typename T>
Builder get_builder()
{
return Builder().foo(T()).bar<T>();
}
int main()
{
auto builder = get_builder<int>();
(void) builder;
}
См. В Wandbox
Clang (9.0.0 ) отклоняет это следующим образом:
prog.cc:22:31: error: use 'template' keyword to treat 'bar' as a dependent template name
return Builder().foo(T()).bar<T>();
^
template
Прав ли Кланг, говоря, что bar
является зависимым именем шаблона? VS 2017 не видит проблем. G CC (9.2.0) также отклоняет код, но с гораздо более неясным сообщением об ошибке:
prog.cc: In function 'Builder get_builder()':
prog.cc:22:36: error: expected primary-expression before '>' token
22 | return Builder().foo(T()).bar<T>();
| ^
prog.cc:22:38: error: expected primary-expression before ')' token
22 | return Builder().foo(T()).bar<T>();
|
Изменение ошибочной строки, как предлагает Clang
return Builder().foo(T()).template bar<T>();
исправляет компиляцию для Clang и G CC. VS2017 также принимает эту версию.
Кажется, решение простое , но если я переупорядочу вызовы функций:
return Builder().bar<T>().foo(T());
или удалим параметр из foo
:
return Builder().foo().bar<T>();
ошибка исчезла.
Что здесь происходит?
- Правильно ли Кланг и G CC отвергнуть оригинальную версию?
- Правильно ли Clang и G CC принимают измененные версии (переупорядочены, изменены
foo
)? Если так, то почему? В чем разница?