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.
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.
Related
I wrote a singleton template class just like boost does:
template <typename _T>
class Singleton
{
public :
static _T* Instance()
{
static _T obj;
return &obj;
}
protected :
Singleton() {}
private :
struct ObjectCreator
{
ObjectCreator()
{
Singleton<_T>::instance();
}
};
static ObjectCreator object_creator;
};
template <typename _T>
typename Singleton<_T>::ObjectCreator Singleton<_T>::object_creator;
And I wrote the main function to test it.
#include "Singleton.h"
class A : public Singleton <A>
{
public:
int a;
};
int main()
{
A::Instance()->a = 2;
}
I know I mistyped Instance in ObjectCreator's constructor, the weird thing is I can compile it correctly by gcc-4.4.7, then I used clang-6.0, it hit me with the typo.
I guess gcc can do some optimization, because I did not do anything with ObjectCreator, so it ignored the error code.
I have two questions:
What should I do to make gcc report me that error (without changing my code), like add some compiler flag?
If anyone has a more reliable explanation for this? Some official doc would do.
Ps: I am aware that boost would add a do_nothing function in ObjectCreate and call it from Singleton<_T>:: Instance() to avoid this optimization.
What should I do to make gcc report that error (without changing my code), like add some compiler flag?
You could add an explicit instantiation template class Singleton<float>; (I just randomly picked float as type, but you could choose anything more appropriate) to force GCC to check for syntax. See https://gcc.godbolt.org/z/ii43qX for an example.
If you simply want the check, you could also put this explicit instanciation to a separate compilation unit by adding another cpp-file to your project.
However, doing an explicit instanciation is stronger than the implicit instanciation, as all members and methods are going to be instanciated. This behavior might be anwanted (see standard library for examples).
If anyone has a more reliable explanation for this? Some official doc would do.
Static members are not initialized implicitly until it is used in a way that its definition is required (this is very different to the explicit instanciation).
#StoryTeller found the right paragraph in the standard
14.7.1 Implicit instantiation [temp.inst]
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, static data members and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions. Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
EDIT
You should accept the answer of #StoryTeller as he correctly explained both aspects of your question first.
If I read the standard correctly, I don't believe your code is ill-formed (bar the use of a _T identifier). Clang going the extra mile is fantastic, but GCC isn't wrong to accept it as is.
The reason is your program only contains an implicit instantiation of your template. According to N19051 (emphasis mine):
14.7.1 Implicit instantiation [temp.inst]
1 ... 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, static data members and member
templates; and it causes the implicit instantiation of the definitions
of member anonymous unions. Unless a member of a class template or a
member template has been explicitly instantiated or explicitly
specialized, the specialization of the member is implicitly
instantiated when the specialization is referenced in a context that
requires the member definition to exist; in particular, the
initialization (and any associated side-effects) of a static data
member does not occur unless the static data member is itself used in
a way that requires the definition of the static data member to exist.
Nothing uses object_creator in a way that requires its definition to exist. As such only the declaration is ever checked. Furthermore, only the declaration of class ObjectCreator is required to be instantiated itself, not its definition (or the definition of its constructor). This is for the same reason one can define an extern variable of a forward declared class type:
extern class C c;
The above paragraph (and the fact nothing uses object_creator) only requires the type name and object name be instantiated, to produce an effect similar to the above external declaration.
As a result GCC never has to verify instance is valid. I would say that given the above paragraph, even if you didn't have a typo, it's quite possible object_creator doesn't do what you think it does. If your code worked, it's only because the function local static obj was initialized on first use (making ObjectCreator redundant).
As for why adding an explicit instantiation (like #P i suggested) immediately causes an error. We can see here:
14.7.2 Explicit instantiation [temp.explicit]
7 The explicit instantiation of a class template
specialization also explicitly instantiates each of its members (not
including members inherited from base classes) whose definition is
visible at the point of instantiation and that has not been previously
explicitly specialized in the translation unit containing the explicit
instantiation.
When we do that, we recursively force everything to be instantiated, and as a result, checked.
1 - This is a 2005 draft. Very close to C++03, and therefore I believe appropriate given your use of GCC 4.4.7.
What should happen if an expression's type is not dependent, but we use it to initialize a static auto variable? GCC and Clang differ in their behavior
template<typename T>
struct A {
static inline auto x = sizeof(T{}.f);
};
A<int> a;
GCC doesn't raise an error. But Clang thinks that this is invalid because it instantiates the operand of "sizeof". GCC appears to skip that step because sizeof(T{}.f) always has type size_t (not type dependent), so it already knows type of x without instantiation. Both compilers conformly reject the program if we refer to x, for example by (void) a.x;.
Does it even have to resolve the type of x at all? With C++14 upwards the language allows keeping things (like functions) with a "placeholder type" and doing delayed instantiation to find out about the actual return type later on, if I remember correctly. Does it have to apply this to x aswell, so keeping x with a placeholder type till we refer to a.x?
What compiler is correct according to the Standards?
EDIT
Someone asked
uhm, shouldnt' this be equivalent to this ?
template<typename T>
struct A {
static const std::size_t x;
};
template<typename T>
inline constexpr std::size_t A<T>::x = sizeof(T{}.f);
The difference, and what concerns me in my question, is that the static data member in my question is auto. Therefore, in order to know the type of x, you need to know the type of the initializer. Clang appears to instantiate the initializer eagerly in order to get the type. But GCC doesn't, apparently? I would like to understand what's going on.
From [temp.inst]/3:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
Simply writing A<int> a; does noes not use A<int>::x in a way that requires its definition to exist, so its initialization should not occur. gcc is correct.
As far as I understand - generic lambdas are transformed into objects of local scope structs with templated operator(). This makes generic lambda very powerful and easy to use tool. On the other hand one can create structs nested into the function, when however the struct has templated member e.g.:
#include <iostream>
int main() {
struct inner {
template <class T>
void operator()(T &&i) { }
};
return 0;
}
or is templated by itself:
int main() {
template <class T>
struct inner {
void operator()(T &&i) { }
};
return 0;
}
compiler seems to have a problem with compiling it:
error: invalid declaration of member template in local class
and
error: a template declaration cannot appear at block scope
I assume the problem lays more in c++ standard than in compiler bug. What are the reasons lambdas are allowed to have templated members and not the local structures?
I found this qustion, but I think the answer is kind of outdated (I don't think it's true even for c++11).
This is core issue 728, which was filed before generic lambdas were a thing.
You mentioned generic lambdas and that they were identical to local classes with corresponding member template operator(). However, they actually aren't, and the differences are related to implementation characteristics. Consider
template <typename T>
class X {
template <typename>
void foo() {
T t;
}
};
And
template <typename T>
auto bar() {
return [] (auto) {T t;};
};
Instantiating these templates with <void> will be fine in the first case, but ill-formed in the second. Why fine in the first case? foo need not be instantiatable for each particular T, but just one of them (this would be [temp.res]/(8.1)).
Why ill-formed in the second case? The generic lambda's body is instantiated - partially - using the provided template arguments. And the reason for this partial instantiation is the fact that…
…the lexical scopes used while processing a function definition are fundamentally transient, which means that delaying instantiation of some portion of a function template definition is hard to support.
(Richard Smith) We must instantiate enough of the local "template" to make it independent of the local context (which includes template parameters of the enclosing function template).
This is also related to the rationale for
[expr.prim.lambda]/13, which mandates that an entity is implicitly captured by a lambda if it…
names the entity in a potentially-evaluated expression ([basic.def.odr]) where the enclosing full-expression depends on a generic lambda parameter declared within the reaching scope of the lambda-expression.
That is, if I have a lambda like [=] (auto x) {return (typename decltype(x)::type)a;}, where a is some block-scope variable from an enclosing function, regardless of whether x's member typedef is for void or not, the cast will cause a capture of a, because we must decide on this without waiting for an invocation of the lambda. For a discussion of this problem, see the original proposal on generic lambdas.
The bottom line is that completely postponing instantiation of a member template is not compatible with the model used by (at least one) major implementation(s), and since those are the expected semantics, the feature was not introduced.
Was that the original motivation for this constraint? It was introduced sometime between January and May 1994, with no paper covering it, so we can only get a rough idea of the prevailing notions from this paper's justification of why local classes shall not be template arguments:
Class templates and the classes generated from the template are global scope
entities and cannot refer to local scope entities.
Perhaps back then, one wanted to KISS.
I assume the problem lays more in c++ standard
Correct. This is stipulated in [temp] for class templates:
A template-declaration can appear only as a namespace scope or class scope declaration.
and [temp.mem] for member templates:
A local class of non-closure type shall not have member templates.
What are the reasons lambdas are allowed to have templated members and not the local structures?
Because once we had lambdas in C++11, it was deemed that it would be extremely useful to extend that concept to have generic lambdas. There was a proposal for such a language extension, which was revised and revised and adopted.
On the other hand, there has not yet been a proposal presented (as far as I'm aware from a brief search) that lays out the motivation for the need for member templates in local classes that isn't adequately solved by a generic lambda.
If you feel that this is an important problem that needs to be solved, feel free to submit a proposal after laying out a thoughtful motivation for why local member templates are important.
Consider this code:
template <int N>
struct X
{
friend void f(X *) {}
};
int main()
{
f((X<0> *)0); // Error?
}
compilers seem to heavily disagree. (MSVC08/10 says no, GCC<4.5 says yes, but 4.5 says no, sun 5.1 says yes, intel 11.1 says yes too but comeau says no (both are EDG)).
According to "C++ Templates - The complete guide":
... it is assumed that a call
involving a lookup for friends in
associated classes actually causes the
class to be instantiated ... Although
this was clearly intended by those who
wrote the C++ standard, it is not
clearly spelled out in the standard.
I couldn't find the relevant section in the standard. Any reference?
Consider this variation:
template <int N>
struct X
{
template <int M>
friend void f(X<M> *) {}
};
template <>
struct X<0>
{
};
int main()
{
X<1>();
f((X<0> *)0); // Error?
}
The key issue here is wether the viable function injected by X<1> should be visible during ADL for X<0>? Are they associated? All compilers mentioned above accept this code, except for Comeau which only accepts it in relaxed mode. Not sure what the standard has to say about this either.
What's your take on that?
The Standard says at 14.7.1/4
A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type affects the semantics of the program; in particular, if an expression whose type is a class template specialization is involved in overload resolution, pointer conversion, pointer to member conversion, the class template specialization is implicitly instantiated (3.2);
Note that Vandervoorde made an issue report here, and the committee found
The standard already specifies that this creates a point of instantiation.
For your second case - you need to consider the associated classes and namespaces of the argument f(X<0>*). These are, since this is a pointer to a class template specialization (note that "template-id" below is not quite correct - C++0x corrected that to use the correct term) and also a pointer to a class (this confusing split was also corrected in C++0x - it lists these two cases in one bullet point).
If T is a template-id, its associated namespaces and classes are the namespace in which the template is
defined; [... lots of noise ...]
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces in which its associated classes are defined.
So to summary, we have as associated classes are X<0> and the associated namespaces are the global namespace. Now the friend functions that are visible are
Any namespace-scope friend functions declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup
There is no friend function declared in X<0> so the friend function declaration is not visible when looking into the global namespace. Note that X<0> is an entirely different class-type than X<1>. The implicit instantiation of X<1> you do there has no effect on this call - it just adds a non-visible name into the global namespace that refers to a friend function of class X<1>.
We all know you can simulate closures in C++98 by defining local structs/classes inside a function. But is there some reason that locally defined structs can't be used to instantiate templates outside of the local scope?
For example, it would be really useful to be able to do things like this:
void work(std::vector<Foo>& foo_array)
{
struct compareFoo
{
bool operator()(const Foo& f1, const Foo& f2) const
{
return f1.bar < f2.bar;
}
};
std::sort(foo_array.begin(), foo_array.end(), compareFoo());
}
This would be especially useful if you know you're not going to need to use compareFoo anywhere else in your code. But, alas, this doesn't compile. Is there some reason that the compiler can't instantiate the std::sort template function using a locally defined struct?
There's no better reason than "it's not allowed by the standard".
I believe C++0x is going to lift this restriction, and allow you to use local classes as template parameters freely. But for now, it's not allowed.
See GOTW #58 - you can't use locally defined classes as arguments to templated types, e.g. vector wouldn't be allowed.
From the C++ standard (14.3.1/2):
A local type, a type with no linkage, an unnamed
type or a type compounded from any of these types
shall not be used as a template-argument for a
template type-parameter. [Example:
template <class T>
class X { /* ... */ };
void f()
{
struct S { /* ... */ };
X<S> x3; // error: local type used as
// template-argument
X<S*> x4; // error: pointer to local type
// used as template-argument
}
--end example]
Although I don't read this as meaning template functions like std::sort can't use a local class as an argument, apparently gcc thinks otherwise.
The local classes have no linkage (no global name), which seems like something that helps overburned compiler writers and hurts actual programmers. To actually allow a local class S to be used in vector<S> or some function<..,S>, I guess the generated thing would need a unique global name.
The way I read the standard, it prohibits using local types as template parameters in general, which would mean both class and function templates.
It says: A local type ... shall not be used as a template-argument for a template type-parameter.
The example it gives uses a class template, but I suppose there's no reason to assume that this restriction is not applicable to template functions.
Anyway, I wonder what the reason for this restriction is. It seems arbitrary.
I know that the question is a bit dated, but an easier solution is to enable the c++0x standard mode in g++ since it already supports template instantiation with locally-defined types.
g++ -std=c++0x filename.cpp -o filename