I have some code that fails to compile, which I reduced to the following minimum version:
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;
}
Clang (9.0.0) rejects this with:
prog.cc:22:31: error: use 'template' keyword to treat 'bar' as a dependent template name
return Builder().foo(T()).bar<T>();
^
template
Is Clang right saying that bar
is a dependent template name? VS 2017 sees no problem. GCC (9.2.0) also rejects the code, but with a much more obscure error message:
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>();
|
Changing the offending line as Clang suggests
return Builder().foo(T()).template bar<T>();
fixes compilation for Clang and GCC. VS2017 also accepts this version.
It seems the solution is simple, but if I reorder the function calls:
return Builder().bar<T>().foo(T());
or remove the parameter from foo
:
return Builder().foo().bar<T>();
the error is gone.
What is going on here?
- Are Clang and GCC right rejecting the original version?
- Are Clang and GCC right accepting the changed versions (reordered, changed
foo
)? If so, why? What is the difference?