Forward declare C++ [duplicate] - c++

The following compiles on GCC 4.8.1 (with --std=c++11):
struct non_default_constructible { non_default_constructible() = delete; };
template<class T>
struct dummy {
T new_t() { return T(); }
};
int main(int argc, char** argv) {
dummy<non_default_constructible> d;
return 0;
}
The tricky part is that dummy<non_default_constructible>::new_t() is obviously ill-formed, but that does not prevent the compiler from instantiating dummy<non_default_constructible>.
Is this the behaviour specified by the standard? And what would be the relevant sections/keywords?

The member functions of a class template are instantiated only when required by a context, which means you will not see any error until you try to use new_t(). The related section from the C++ standard is:
§ 14.7.1 Implicit instantiation [temp.inst]
Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[ Example:
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
Nothing in this example requires class Z<double>, Z<int>::g(), or Z<char>::f() to be implicitly
instantiated. — end example ]

Related

Does an explicit instantiation declaration of a member function of a class template cause instantiation of the class template?

[dcl.spec.auto]/14 states [emphasis mine]:
An explicit instantiation declaration does not cause the instantiation of an entity declared using a placeholder type, but it also does not prevent that entity from being instantiated as needed to determine its type. [ Example:
template <typename T> auto f(T t) { return t; }
extern template auto f(int); // does not instantiate f<int>
int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit
// instantiation definition is still required somewhere in the program
 — end example ]
and [temp.explicit]/11 states [emphasis mine]:
An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.
Now, consider the following program:
template <class T>
struct Foo {
static const auto& foo() { static T t; return t; }
};
// explicit instantiation declarations
extern template const auto& Foo<void>::foo();
extern template const auto& Foo<int>::foo();
int main() {}
This is well-formed; [temp.explicit]/11 does not apply as neither member function of class template specialization entities Foo<void>::foo() nor Foo<int>::foo() are used in a way that would otherwise cause an implicit instantiation, as per [dcl.spec.auto]/14(1).
Now, consider if we defined a friend function at its friend declaration in the class template Foo:
template <class T>
struct Foo {
static const auto& foo() { static T t; return t; }
friend void bar() { }
};
void bar();
If any more than one specialization of Foo is instantiated in the same translation unit, [basic.def.odr]/1 will be violated:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
as the friend bar() would be re-defined(2) for each specialization that is instantiated.
According to the argument above, the explicit instantiation declarations of the two member function (of class template) specializations should not lead to any instantiation of the associated class template (as per [dcl.spec.auto]/14), meaning the following program should also arguably be well-formed:
template <class T>
struct Foo {
static const auto& foo() { static T t; return t; }
friend void bar() { }
};
void bar();
extern template const auto& Foo<void>::foo();
extern template const auto& Foo<int>::foo();
int main() {}
However, both Clang (10.0.0) and GCC (10.1.0) rejects the program (C++14, C++17, C++2a) with a "redefinition of void bar()” error:
Clang
error: redefinition of bar
note: in instantiation of template class Foo<int> requested here:
extern template const auto& Foo<int>::foo();
GCC
In instantiation of struct Foo<int>:
error: redefinition of void bar()
But I never requested (or, afaict, used these specializations in a way such that) the Foo<int> or Foo<void> specializations (are) to be instantiated.
Thus to the question:
Is the program (with the friend) above well-formed, or are the compilers correct to instantiate the class template specializations and subsequently reject the program?
(1) Note the the same question (and compiler behaviour) applies even if foo() is not declared using a placeholder type, but then we would not be able to fall back on the explicitness of [dcl.spec.auto]/14, but we may not need to.
(2) As friends defined at their friend declaration are inline, we may actually instantiate different specializations in different translation units and still respect ODR, but this is not relevant in this discussion.
The argument that the class template must be instantiated is that declaration matching may need to know things about the class that plainly require instantiation. Consider the simplified example
template<class T>
struct A {void f(T) {}};
extern template void A<int>::f(int);
To know whether the member function exists, we must instantiate the declaration in the class template, and we can’t do that in general without instantiating the whole class: the parameter type could depend on any other declarations in the class template, and we might need to consider multiple overloads or even do template argument deduction to decide which f is meant. One can argue that instantiation should happen only if one of these situations actually pertains, which strays into CWG2 territory (where instantiation is obviously impossible), but the idea is that instantiation is necessary in principle to decide about such questions because we simply don’t try examining the template itself first.

Method in template class only for certain template parameters correct

Consider the following template class
template<typename T>
struct Caller {
void func(const T &t) { t.func(); }
void gunc(const T &t) { t.gunc(); }
};
Now let some class Target only provide the member function func() but not gunc(), i.e.
struct Target {
void func() const { /* ... /* }
};
is the template instantiation Caller<Target> valid?
GCC, clang as well as VC++ accept such template instantiations. Of course, calling Caller<Target>::gunc() leads to an error but Caller<Target>::func() works just fine and as intended.
Now the question: What is the background for this permissive behavior and where are the relevant paragraphs in C++ standard.
It's specified in the standard, under Templates (14), Template instantiation and specialization (14.7), Implicit instantiation (14.7.1).
3 Unless a function template specialization has been explicitly
instantiated or explicitly specialized, the function template
specialization is implicitly instantiated when the specialization is
referenced in a context that requires a function definition to exist.
And
11 An implementation shall not implicitly instantiate a function
template, a member template, a non-virtual member function, a member
class, or a static data member of a class template that does not
require instantiation.

static_assert fails check on templated object pointer

template <size_t N>
class Foo
{
static_assert(N > 0, "WRONG");
//void Something() = 0; //my original implementation
};
int main() {
Foo<0> *p2 = nullptr; //no error
Foo<0> p; //gives an error
return 0;
}
I've tested both the lines separately. static_assert is not called when p2 is initialized but it is called and does indeed fail on p. Is this intended? (I've tried it on gcc, clang and VC)
What are the workarounds? Since I'm using abstract templated classes, it would be a nightmare if the assertion is only performed when a non-pointer object is instantiated. I can use a factory but that isn't exactly a proper solution.
You assuredly saw this quote from §14.7.1/1:
Unless a class template specialization has been explicitly
instantiated (14.7.2) or explicitly specialized (14.7.3), the class
template specialization is implicitly instantiated when the
specialization is referenced in a context that requires a
completely-defined object type or when the completeness of the class
type affects the semantics of the program.
Pointer types do not require their pointee to be a complete type (e.g. void* is an example of this). Thus the first line will not instantiate the specialization, but the second one needs to, hence the assertion fires only on that one.
This is also addressed by an example three paragraphs further down:
[ Example:
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<double>* q; // instantiation of class Z<double> not required
//[…]
}
Nothing in this example requires class Z<double> […] to be implicitly instantiated. — end example ]

Member function instantiation

The following compiles on GCC 4.8.1 (with --std=c++11):
struct non_default_constructible { non_default_constructible() = delete; };
template<class T>
struct dummy {
T new_t() { return T(); }
};
int main(int argc, char** argv) {
dummy<non_default_constructible> d;
return 0;
}
The tricky part is that dummy<non_default_constructible>::new_t() is obviously ill-formed, but that does not prevent the compiler from instantiating dummy<non_default_constructible>.
Is this the behaviour specified by the standard? And what would be the relevant sections/keywords?
The member functions of a class template are instantiated only when required by a context, which means you will not see any error until you try to use new_t(). The related section from the C++ standard is:
§ 14.7.1 Implicit instantiation [temp.inst]
Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.
[ Example:
template<class T> struct Z {
void f();
void g();
};
void h() {
Z<int> a; // instantiation of class Z<int> required
Z<char>* p; // instantiation of class Z<char> not required
Z<double>* q; // instantiation of class Z<double> not required
a.f(); // instantiation of Z<int>::f() required
p->g(); // instantiation of class Z<char> required, and
// instantiation of Z<char>::g() required
}
Nothing in this example requires class Z<double>, Z<int>::g(), or Z<char>::f() to be implicitly
instantiated. — end example ]

Why does function calls to templatized base classes not work?

Consider the following example:
template <typename T>
class A {
public:
void f() {
cout << "A::f()\n";
}
};
template<>
class A<int> {
};
template<typename T>
class B: public A<T> {
public:
void g() {
cout << "B::g()\n";
A<T>::f();
}
};
int main() {
B<int> b; // (1)
b.g(); // (2)
return 0;
}
Obviously the call to A::f() inside B::g() will fail for int template type. My question is at what point does the call fail? At (1) or (2)? I thought it should be (1) because at that point the compiler creates a new class with the template type int and compiles it. That compilation should fail in f() correct?
It will fail at (2), and this is guaranteed by the standard. In section 14.7.1/1, it says instantiating a template class does not instantiate it's members definitions. That will only happen once the member is used.
If you remove (2) from the code, it will compile.
14.7.1/1 excerpt:
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.
Emphasis mine.
Visual Studio's diagnosis is misleading. It will say see reference to class template instantiation 'B<T>' being compiled. What it means is not "I'm failing at the instantiation of B<T>", but "I'm failing at instantiating a member of the class B<T>"
It fails at 2). Member function of templates are instantiated when called.
More precisely: When a class template is instantiated, the declaration of its member functions are instantiated, but not their definition. The definition is instantiated when the function is used.