Question

Here is a short self-contained test case to explain my question. GCC accepts this code, but clang and Intel reject it:

template <typename T>
struct false_t {
  static const bool value = false;
};
template <typename T>
int f() {
  static_assert(false_t<T>::value, "");
  return 0;
}
template <typename T>
struct S {
  int m = f<T>();
};
int s = sizeof(S<int>);

Or, based on pmr's comment, here is a simpler example which too is accepted by gcc and rejected by clang:

struct S;
template <typename T> struct X { int x = T(); };
int s = sizeof(X<S>);

sizeof(S<int>) (or sizeof(X<S>)) is supposed to instantiate the bits of the class it needs, but the compilers disagree on which bits those are. Since a non-static data member initializer would only be used by a constructor, GCC performs the instantiation as part of instantiating the class's constructor. clang and Intel do so earlier.

I'm having trouble understanding what the standard says in [temp.inst]p1:

The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, scoped member enumerations, static data members and member templates; and it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions.

because I don't see where even the declarations of the non-static data members (with or without initialisers) get instantiated at all.

A bit more details about where I encountered this: I was trying to create a template helper class (that would never be created at runtime) containing a member initialised using std::declval<T>() (which, I should add, I now realise wouldn't be of much use anyway), and libstdc++'s implementation of std::declval contains a static assertion like the one in my example. I can work around the problem without much effort by avoiding std::declval, but I would like to know what the standard requires.

Was it helpful?

Solution

While attempting to figure out how to ask this question, I stumbled upon the answer, but thought it might be useful to post anyway.

This is one of the open issues of the C++ standard, issue 1396 to be precise. The intent is that the initialisers only get instantiated as needed:

Non-static data member initializers get the same late parsing as member functions and default arguments, but are they also instantiated as needed like them? And when is their validity checked?

Notes from the October, 2012 meeting:

CWG agreed that non-static data member initializers should be handled like default arguments.

but there are quite a number problems with that approach that are still being resolved. Until they are resolved, it's only natural that different compilers perform the instantiation at different times, and code that requires specific behaviour should be rewritten to avoid such a requirement. In my case, that means not using std::declval.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top