When is required instantiation of function template definition? - c++

After I read the answer for this question, I am still asking question. The answer talks about location of point of instantiation as defined in [temp.point] but it is not evaluated if the instantiations are required.
[temp.inst] specifies when a function template specialization instantiation is required, the general rule is:
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class,[...], unless such instantiation is required.
Moreover in some paragraph of this section of the standard, instantiation of declaration and instantiation of definition are considered separately.
Let's consider this code:
static void Yeap0(int);
template <class T>
void Yeap(T a){
Yop(a);
}
template <class T>
auto Yeap2(T a){
Yop(a);
return 0;
}
namespace x{
struct y{};
}
int main() {
Yeap0(0);//ok no definition required here
x::y ax{};
Yeap(ax); //the declaration is sufficient,
Yeap2(ax); //need to deduce auto => definition required
//compilation error
return 0;
}
namespace x{
void Yop(y){}
}
static void Yeap0(int){}
Gcc, Clang and MSVC produce only an error for Yeap2(ax), complaining that Yop is not defined at the point of instantiation of Yeap2.
But this error is not generated for Yeap(ax). From basic consideration this seems logical, only the declaration is needed, as for the none template function Yeap0.
But the lecture of [temp.inst]/4 let me perplex. It could be understood that the instantiation of Yeap is also required. But it seems that compilers have taken a more clever path.
Is the compilers behavior an extension?
Note: I will not accept the "no diagnostic required" answer. This would be an insult to intelligence: Could one believe that 3 compilers have taken special care to shut down diagnostics for case like Yeap(ax) but not for Yeap2(ax)?

The compiler complaining really comes from the fact that the function returns auto.
In the auto case you really hit
unless such instantiation is required.
which must come from the requirement dcl.spec.auto.
To verify that assessment you can replace in your code Yeap2 by:
template <class T>
auto Yeap2(T a){
Yeap(a);
return 0;
}
and there is no compilation error.

Related

Behaviour of friend function template returning deduced dependent type in class template

I've happened across the following code, the behaviour of which is diagreed upon by all of GCC, Clang, and MSVC:
#include <concepts>
template<typename T>
auto foo(T);
template<typename U>
struct S {
template<typename T>
friend auto foo(T) {
return U{};
}
};
S<double> s;
static_assert(std::same_as<decltype(foo(42)), double>);
Live demo: https://godbolt.org/z/hK6xhesKM
foo() is declared at global namespace with deduced return type. S<U> provides a definition for foo() via a friend function, where it returns a value of type U.
What I expected is that when S is instantiated with U=double, its definition of foo() gets put in the global namespace and U is substituted in, due to how friend functions work, effectively like this:
template<typename T>
auto foo(T);
S<double> s;
template<typename T>
auto foo(T) {
return double{};
}
Thus I expect foo()'s return type is double, and the following static assertion should pass:
static_assert(std::same_as<decltype(foo(42)), double>);
However, what actually happens is that all three compilers disagree on the behaviour.
GCC passes the static assertion, like I expect.
Clang fails the static assertion, as it seems to believe that foo() returns int:
'std::is_same_v<int, double>' evaluated to false
And MSVC produces a different error entirely:
'U': undeclared identifier
I find it bizarre that all the compilers have different behaviour here for a seemingly simple code example.
The issue does not occur if foo() isn't templated (see demo here), or if it doesn't have deduced return type (see demo here).
Which compiler has the correct behaviour? Or, is the code ill-formed NDR or undefined behaviour? (And, why?)
Which compiler has the correct behaviour? Or, is the code ill-formed NDR or undefined behaviour? (And, why?)
As #Sedenion points out in a comment, whilst touching upon the domain of CWG 2118 (we'll return to this further down) this program is by the current standard well-formed and GCC is correct to accept it, whereas Clang and MSVC are incorrect to reject it, as governed by [dcl.spec.auto.general]/12 and /13 [emphasis mine]:
/12 Return type deduction for a templated entity that is a function or function template with a placeholder in its declared type
occurs when the definition is instantiated even if the function body contains a return statement with a non-type-dependent operand.
/13 Redeclarations or specializations of a function or function template
with a declared return type that uses a placeholder type shall also
use that placeholder, not a deduced type. Similarly, redeclarations or
specializations of a function or function template with a declared
return type that does not use a placeholder type shall not use a
placeholder.
[Example 6:
auto f();
auto f() { return 42; } // return type is int
auto f(); // OK
// ...
template <typename T> struct A {
friend T frf(T);
};
auto frf(int i) { return i; } // not a friend of A<int>
Particularly the "not a friend of A<int>" example of /13 highlights that the redeclaration shall use a placeholder type (frf(T), and not a deduced type (frf(int)), whereas otherwise that particular example would be valid.
/12, along with [temp.inst]/3 (below) covers the that return type deduction for the friend occurs only after the friend's primary template definition has been made available (formally: it's declaration but not definition has been instantiated) from the instantiation of the S<double> enclosing class template specialization.
The implicit instantiation of a class template specialization causes
(3.1) the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member
classes, scoped member enumerations, static data members, member
templates, and friends; and
[...]
However, for the purpose of determining whether an instantiated
redeclaration is valid according to [basic.def.odr] and [class.mem], a
declaration that corresponds to a definition in the template is
considered to be a definition.
[Example 4:
// ...
template<typename T> struct Friendly {
template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // error: produces second definition of f(U)
— end example]
CWG 2118: Stateful metaprogramming via friend injection
As covered in detail e.g. in A foliage of folly, one can rely on the single first instantiation of a class template to control how the definition of a friend looks like. First here means essentially relying on meta-programming state to specify this definition.
In OP's example the first instantiation, S<double>, is used to set the definition of the primary template of the friend foo such that its deduced type will always deduce to double, for all specializations of the friend. If we ever (in the whole program) instantiate, implicitly or explicitly, a second instantiation of S (ignoring S being specialized to remove the friend), we run into ODR-violations and undefined behavior. This means that this kind of program is, in practice, essentially useless, as it would serve clients undefined behavior on a platter, but as covered in the article linked to above it can be used for utility classes to circumvent private access rules (whilst still being entirely well-formed) or other hacky mechanisms such as stateful metaprogramming (which typically runs into or beyond the grey area of well-formed).

How to check that a C++ class is incomplete (only declared)?

I would like to write a C++ function that will check that its template parameter class is incomplete, so only class declaration is available but not full definition with all class members.
My function incomplete() looks as follows together with some demo program:
#include <type_traits>
#include <iostream>
template <typename T, typename V = void> constexpr bool is_incomplete = true;
template <typename T> constexpr bool is_incomplete<T, std::enable_if_t<sizeof(T)>> = false;
template <typename T> constexpr bool incomplete() { return is_incomplete<T>; }
struct A;
void print() { std::cout << incomplete<A>(); }
struct A {}; //this line affects GCC
int main()
{
print();
}
It works well in Clang printing 1, but in GCC the program prints 0 despite the fact that A class is incomplete in function print.
https://gcc.godbolt.org/z/qWW3hqbEv
Is GCC wrong here or there is a fault in my program?
Which compiler is correct is currently undecided. It's CWG Issue 1845.
The current wording of 13.8.4.1 [temp.point] does not define the point of instantiation of a variable template specialization. Presumably replacing the references to “static data member of a class template” with “variable template” in paragraphs 1 and 8 would be sufficient.
Given that issue is still in drafting stage (and no normative wording exists yet it the latest available draft), it remains unresolved. It isn't clear if a variable template can have multiple points of instantiation or not (though the direction the issue reporter suggests is clear).
For entities with multiple points of instantiation, the end of the translation unit is one as well. Also, if two points disagree on the definition of template, it's an ODR violation, plain and simple. GCC seems to provide two points, so you see the result of that. And I tend to agree with GCC here. A variable template is in many ways a shorthand for a static data member of a class template, and static data members do have multiple points of instantiation.
Either way, this is playing with the risk of nasal demons. Checking a type for complete-ness is not really possible reliably if that state can change in a TU (and possibly even if it can change in the entire program).
It looks like the finding whether a class is incomplete will be a violation of one definition rule (ODR) if at some point it becomes complete, so there should be no valid solution to the question.
Some more quotes from https://eel.is/c++draft/temp.point that I was suggested:
1 For a function template specialization ... the point of instantiation ... immediately follows the namespace scope declaration or definition that refers to the specialization.
7 A specialization for a function template ... may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above,
for any such specialization that has a point of instantiation within the ... the translation-unit ..., the point after the ... [end of] the translation-unit is also considered a point of instantiation,
If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.

If a function template has deduced return type, is there a way to call it without instantiating the definition?

Consider some function template such as:
template <class T>
const auto& foo() { static T t; return t; }
The definition would not be valid if T were to be void. Nonetheless, we are allowed to instantiate the declaration alone without triggering an error:
extern template const auto& foo<void>(); // explicit instantiation declaration
Now let's consider situations where foo is called, rather than being explicitly instantiated. Obviously, if foo is ever called in an evaluated context, the definition of the specialization will be instantiated. What about in an unevaluated context? We know that if a function template with a non-deduced return type is called in an unevaluated context, the definition of the specialization is not instantiated. The obvious example of this is std::declval<T>. It's not clear whether the same is possible for a function that has a deduced return type.
For example, I considered this:
static_assert(sizeof( (void)foo<void>(), char{} ) == 1);
However, even in this situation, where the compiler definitely has enough information to evaluate the sizeof expression without knowing the return type, a compilation error still occurs (godbolt link).
What provision of the Standard requires the instantiation of the definition of foo<void> in this situation?
Is there any way that foo<void> can be called inside an unevaluated expression that would not instantiate its definition?
What provision of the Standard requires the instantiation of the definition of foo<void> in this situation?
Albeit non-normative, the note in [dcl.spec.auto]/11 does mention that any use of a specialization (of a function template with a placeholder in its declared return type) will cause an implicit instantiation [extract, emphasis mine]:
[...] [ Note: Therefore, any use of a specialization of the function template will cause an implicit instantiation.
and, moreover, [dcl.spec.auto]/14 covers the particular case of allowing an explicit instantiation declaration without triggering an instantiation, whilst arguably also hinting that the instantiation mechanisms triggered for determining the return type for a function template are somewhat separated from the "regular" instantiation mechanisms [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 ]
where the comment (non-normative) to the example points out that such a special-case triggered implicit instantiation is only used for return type deduction, and does not waive the need for an explicit instantiation definition elsewhere.
Is there any way that foo<void> can be called inside an unevaluated expression that would not instantiate its definition?
Given the discussion above, I would say: no. Calling even within an unevaluated expression would fall under the (non-normative) "any use of".

Calling function templates specialized in another translation unit [duplicate]

This question already has answers here:
Should I declare my function template specializations or is defining them enough?
(2 answers)
Is it safe to place definition of specialization of template member function (withOUT default body) in source file?
(3 answers)
Closed 2 years ago.
I'm working on a codebase which uses the following structure:
a.h:
template<int N> void f();
void b();
a.cpp:
#include "a.h"
template<> void f<1>() {}
int main()
{
b();
}
b.cpp:
#include "a.h"
void b()
{
f<1>();
}
The code appears to build and run correctly.
My question is: is this well-formed, or is it some kind of ill-formed NDR that happens to work?
If building with clang -Wundefined-func-template (this was enabled in my IDE's default settings for clang-tidy) then a warning is produced:
b.cpp:5:2: warning: instantiation of function 'f<1>' required here, but no definition is available [-Wundefined-func-template]
f<1>();
^
./a.h:1:22: note: forward declaration of template entity is here
template<int N> void f();
^
b.cpp:5:2: note: add an explicit instantiation declaration to suppress this warning if 'f<1>' is explicitly instantiated in another translation unit
f<1>();
^
But I am not sure whether to just disable the warning, or make some code change (other than moving the explicit specialization definition to the header file, which would not be preferable for this project).
Following the advice in the warning message and adding an explicit instantiation declaration to the header file (i.e. extern template void f<1>();) caused an error message (implicit instantiation of a specialization before explicit instantiation).
However, adding an explicit specialization declaration template<> void f<1>(); to the header file suppresses the warning. But I am not sure if this is (a) necessary, and/or (b) recommended style.
The program violates [temp.expl.spec]/6:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.
The function template f is explicitly specialized by template<> void f<1>() {} in b.cpp. But in the translation unit formed from b.cpp and including a.h, the statement f<1>(); would cause an implicit instantiation of the same specialization f<1>, and there is no declaration of the explicit specialization earlier (or anywhere) in the translation unit.
Per the Standard, an explicit specialization is always a distinct thing from an instantiated specialization, since both can never exist for the same primary template and same template arguments. But the program might work anyway because many compilers use the same mangled linker names for template explicit specializations and instantiated specializations.
The clang warning might be because it's legal, though unusual, to implicitly instantiate a function template without a visible definition if the same specialization is explicitly instantiated, not explicitly specialized, elsewhere. So it's suggesting an improvement to make a legal program clearer. I'm not exactly sure if it actually is legal, though. But its suggested explicit instantiation declaration would be a lie, since the specialization is explicitly specialized, not explicitly instantiated.
The program does become valid if you add explicit specialization declarations to the header file for every specialization which will be used.
template<int N> void f();
template<> void f<1>();
There's an example in [temp.over]/5 that matches yours almost exactly, and pronounces it well-formed:
[temp.over]/5 ... [ Example:
template<class T> void f(T); // declaration
void g() {
f("Annemarie"); // call of f<const char*>
}
The call of f is well-formed even if the template f is only declared and not defined at the point of the call. The program will be ill-formed unless a specialization for f<const char*>, either implicitly or explicitly generated, is present in some translation unit. —end example ]
[temp]/7 says:
A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated unless the corresponding specialization is explicitly instantiated in some translation unit; no diagnostic is required.
The standard requires explicit instantiation, so explicit specialization in a.cpp won't make the program well-formed.
A similar question ([temp]/7 treats function templates and member functions of class templates equally) was asked in CWG2138:
It is not clear whether the following common practice is valid by the current rules:
// foo.h
template<typename T> struct X {
int f(); // never defined
};
// foo.cc
#include "foo.h"
template<> int X<int>::f() { return 123; }
// main.cc
#include "foo.h"
int main() { return X<int>().f(); }
which was closed as NAD with the following rationale:
As stated in the analysis [which referred to [temp]/7, among other things], the intent is for the example to be ill-formed, no diagnostic required.
So, the answer is: the program is ill-formed NDR, and this is intended.

Is it safe to place definition of specialization of template member function (withOUT default body) in source file?

Here's what I mean:
// test.h
class cls
{
public:
template< typename T >
void f( T t );
};
-
// test.cpp
template<>
void cls::f( const char* )
{
}
-
// main.cpp
int main()
{
cls c;
double x = .0;
c.f( x ); // gives EXPECTED undefined reference (linker error)
const char* asd = "ads";
c.f( asd ); // works as expected, NO errors
return 0;
}
This is completely fine, right?
I started doubting this, because I just ran over the specialization of '...' after instantiation error, which was new to me. So, I "worked around" this error and everything seems to work fine now, but still..
Is this well-defined behavior?
edit: And the same for non-member template functions (forward declared non-member template functions).
Lightness Races in Orbit cited why it's not compliant parts from the Standard. There might be some others, in the vicinity.
I will try to explain in simpler terms what the Standard verbiage means, and hopefully I'll get it correctly, and finally explain the linker errors (or absence of error):
What is the point of instantiation ?
How does the compiler select a specialization ?
What is necessary at the point of instantiation ?
Why a linker error ?
1/ What is the point of instantiation ?
The point of instantiation of a template function is the point where it is called or referred to (&std::sort<Iterator>) with all the template parameters fleshed out (*).
template <typename T>
void foo(T) { std::cout << typeid(T).name() << "\n"; }
int main() { foo(1); } // point of instantiation of "foo<int>(int)"
It can be delayed though, and thus not match the exact call site, for templates called from other templates:
template <typename T>
void foo(T) { std::cout << typeid(T).name() << "\n"; }
template <typename T>
void bar(T t) { foo(t); } // not a point of instantiation, T is still "abstract"
int main() { foo(1); } // point of instantiation of "bar<int>(int)"
// and ALSO of "foo<int>(int)"
This delay is very important as it enables writing:
co-recursive templates (ie, templates that refer to each-others)
user-specializations
(*) Roughly speaking, there are exceptions such as non-template methods of a template class...
2/ How does the compiler select a specialization ?
At the point of instantiation, a compiler need to be able to:
decide which base template function to call
and possibly, which of its specializations to call
This old GotW shows off the woes of specializations... but in short:
template <typename T> void foo(T); // 1
template <typename T> void foo(T*); // 2
are overloads, and each spawns a distinct family of possible specializations of which they are the base.
template <> void foo<int>(int);
is a specialization of 1, and
template <> void foo<int*>(int*);
is a specialization of 2.
In order to resolve the function call, the compiler will first pick the best overload, while ignoring template specializations, and then, if it picked a template function, check if it has any specialization that could better apply.
3/ What is necessary at the point of instantiation ?
So, from the way a compiler resolve the call, we understand why the Standard specifies that any specialization should be declared before its first point of instantiation. Otherwise, it simply would not be considered.
Thus, at the point of instantiation, one needs to have already seen:
a declaration of the base template function to be used
a declaration of the specialization to be selected, if any
But what of the definition ?
It is not needed. The compiler assumes it will either be provided later on in the TU or by another TU entirely.
Note: it does burden the compiler because it means it needs to remember all the implicit instantiations it encountered and for which it could not emit a function-body so that when it finally encounters the definition it can (at last) emit all the necessary code fo all the specializations it encountered. I wonder why this particular approach was selected, and also wonder why even in the absence of an extern declaration the TU may end with undefined function-bodies.
4/ Why a linker error ?
Since no definition is provided, gcc trusts you to provide it later and simply emits a call to an unresolved symbol. If you happen to link with another TU that provides this symbol, then everything will be fine, and otherwise you'll get a linker error.
Since gcc follows the Itanium ABI we can simply look up how it mangles the symbols. It turns out that the ABI makes no difference in mangling specializations and implicit instantiations thus
cls.f( asd );
calls _ZN3cls1fIPKcEEvT_ (which demangles as void cls::f<char const*>(char const*)) and the specialization:
template<>
void cls::f( const char* )
{
}
also produces _ZN3cls1fIPKcEEvT_.
Note: it is not clear to me whether an explicit specialization could have been given a different mangling.
No, I don't think it's okay:
[C++11: 14/6]: A function template, member function of a class template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.
[C++11: 14.7.3/6]: If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. [..]
Frankly I can't explain why it works for you.
I think that your original code was incorrect and your "workaround" is not standard-compliant, too (despite the fact that your compiler and linker process it). Good quotes from the standard were cited in the answer of #Lightness Races in Orbit. See also the following example from the standard ([temp.expl.spec] 14.7.3/6):
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template
// sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization
// after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
I marked my answer as community wiki because in fact it is only a big comment.