Consider this code:
#define SOLUTION 0
template <class T>
constexpr int one = 1;
template <class T>
struct A {
static constexpr int o = one<A<T>>;
void call() {
static_assert(one<A<T>> == 1, "Failure");
}
};
int main() {
#if SOLUTION
A<int> object;
#endif
[](A<int> a) {
a.call();
};
return 0;
}
It builds successfully here on ideone, regardless of the value of SOLUTION define.
Now, I know that this code makes little practical sense, but that is because I was trying earnestly to find the minimal working example of this strange behaviour. If I build this with the latest Visual Studio 2017 (platform toolset v141, _MSC_VER = 1910), I get the following error:
1>source.cpp(11): error C2131: expression did not evaluate to a constant
1>source.cpp(11): note: failure was caused by a read of an uninitialized symbol
1>source.cpp(11): note: see usage of 'one<A<int>>'
1>source.cpp(10): note: while compiling class template member function 'void A<int>::call(void)'
1>source.cpp(21): note: see reference to function template instantiation 'void A<int>::call(void)' being compiled
1>source.cpp(21): note: see reference to class template instantiation 'A<int>' being compiled
Funnily enough, when I put 1 for the SOLUTION macro, it builds successfully. The only difference is that an unused A<int> object; variable is defined in main's scope before the compiler gets to the lambda definition.
It is also perfectly fine if, before main, I define a function like this:
void f(A<int>& a) {
a.call();
}
In fact it solves the problem equally well as does the variable definition.
Is it a compiler bug or is the above chunk of code in violation of the standard?