Is this partial function template specialization? - c++

I came up with this after answering this question
I had a simple function template (C++11):
template<class elem_t, class list_t>
bool in_list(const elem_t& elem, const list_t& list) {
for (const auto& i : list) {
if (elem == i) {
return true;
}
}
return false;
}
But GCC emitted warnings because it doesn't seem to like deducing a template parameter as a std::initializer_list. So, without thinking, I made a specialization:
template<class elem_t>
bool in_list(const elem_t& elem, std::initializer_list<elem_t> list) {
for (const auto& i : list) {
if (elem == i) {
return true;
}
}
return false;
}
This worked. No more warnings. But when I looked again and thought about it, I remembered that C++ does not support partial template specialization on function templates. But that is what this appears to be. My only guess is that this is allowed because std::initializer_list is still dependent upon the template parameter, so it is, in essence, a different template. But I'm not sure if this is how it is supposed to be (isn't there a gotw about templates not overloading?).
Is it standard behavior to accept this? And why?
And as a bonus question, why does GCC not like deducing a template parameter as a std::initializer_list? It seems quite silly to expect me to copy and paste the code and just replace the parameter with a std::initializer_list.
The warning message:
test.cpp: In function ‘int main()’:
test.cpp:33:43: warning: deducing ‘const list_t’ as ‘const std::initializer_list<int>’ [enabled by default]
test.cpp:6:6: warning: in call to ‘bool in_list(const elem_t&, const list_t&) [with elem_t = int, list_t = std::initializer_list<int>]’ [enabled by default]
test.cpp:33:43: warning: (you can disable this with -fno-deduce-init-list) [enabled by default]
When called by in_list(3, {1, 2, 3, 4, 5});
EDIT: Apparently deducing a template parameter as an initializer_list is an extension according to the working draft for my version of GCC (cite). So new question: Is this still an extension as of the final c++11 standard? If so, this would mean that it would be necessary for me to add the second function for standards-compliant code. Thanks for all your help!
EDIT2: The compiler dialect flag appears to be removed for GCC 4.7, so it seems like the issue was resolved, but I don't know how it was resolved.

Using what #Ben Voigt said in the comments on the other answer, I have gathered some relevant standard quotes:
§14.5.6.2
A function template can be overloaded with other function templates
and with normal (non-template) functions. A normal function is not
related to a function template (i.e., it is never considered to be a
specialization), even if it has the same name and type as a
potentially generated function template specialization.
So that rules out function template specialisation as what you're doing, because even if two function template overloads could potentially generate the same function, it's not specialisation. So it's overloading.
Such specializations are distinct functions and do not violate the one definition rule (3.2).
So they're distinct functions and that's why it's not erroring.
§14.5.6.2.1
If a function template is overloaded, the use of a function template
specialization* might be ambiguous because template argument deduction
(14.8.2) may associate the function template specialization with more
than one function template declaration.
This is priming is for what we both already saw, which is that in_list(a, b) where b is an initializer_list appears to match both function templates.
(*Note that "function template specialization" here doesn't mean specialising a function template, it means a function template that has been instantiated with a type. So with template<typename T> f();, f<int>() is a function template specialisation.)
So we use what is called partial ordering of overloaded function templates to resolve this:
Partial ordering of overloaded function template declarations is
used in the following contexts to select the function template to which a function
template specialization
refers:
— during overload resolution for a call to a function template specialization (13.3.3);
— when the address of a function template specialization is taken;
— when a placement operator delete that is a function template specialization is selected to match a placement operator new (3.7.4.2, 5.3.4);
— when a friend function declaration (14.5.4), an explicit instantiation (14.7.2) or an explicit specialization (14.7.3) refers to a function template specialization.
Ok, so that's when partial ordering is for. This is what it does:
Partial ordering selects which of two function templates is more
specialized than the other by transforming each template in turn (see
next paragraph) and performing template argument deduction using the
function type. The deduction process determines whether one of the
templates is more specialized than the other. If so, the more
specialized template is the one chosen by the partial ordering
process.
And then you get into the long and laborious process of determining which template is more specialised, which you can read about if you want, but it's really complicated and I probably don't understand it all (and plus, I don't have enough time to write about it :)).

That's not partial specilization. What you are doing is overloading function.

Related

Template instantiation of templated class constructor

This fails to compile with clang++, can anybody explain why ? (this compiles fine with g++)
struct X
{
template <typename T> X() {}
};
template X::X<int>();
int main() { return 1; }
instantiate.cc:7:13: error: qualified reference to 'X' is a constructor name rather than a type in this context
template X::X<int>();
^
instantiate.cc:7:14: error: expected unqualified-id
template X::X<int>();
^
2 errors generated.
Constructors don't have names. As much is said in [class.ctor]/1. They are special members that get defined by using the name of the class. But they themselves are nameless. While C++ allows us to reference c'tors in certain contexts by using the class name, those are limited. In general, we cannot name a c'tor.
And that is where the issue lies. To explicitly specify template arguments we must use the name of the templated entity. Constructors don't have names, and so we cannot specify their arguments explicitly.
This is the subject of a note in [temp.arg.explicit] that summarizes the intent of the normative text.
7 [ Note: Because the explicit template argument list follows the
function template name, and because conversion member function
templates and constructor member function templates are called without
using a function name, there is no way to provide an explicit template
argument list for these function templates.  — end note ]
We can still instantiate or specialize constructors, but only if the template arguments don't have to be explicitly specified (if they are deducible, or come from a default template argument). E.g
struct X
{
template <typename T> X(T) {}
};
template X::X(int); // This will work
So Clang is not wrong to reject your code. And it's possible GCC is offering an extension. But ultimately, the standard doesn't offer a way to provide template arguments explicitly to constructor templates.
And upon further digging, there's CWG581, further confirming Clang's behavior is the intended one. It also seems to have made its way into the latest standard revision with some changes to the normative text.
I think Clang is correct. Even Gcc allows it, the templated constructor can't be used at all. The template parameter can't be deduced and we can't specify template argument explicitly for constructor template.
[temp.arg.explicit]/2
Template arguments shall not be specified when referring to a specialization of a constructor template ([class.ctor], [class.qual]).
[temp.arg.explicit]/8
[ Note: Because the explicit template argument list follows the function template name, and because constructor templates ([class.ctor]) are named without using a function name ([class.qual]), there is no way to provide an explicit template argument list for these function templates. — end note ]

what is the order of the function template instantiation,substitution and overload resolution

#include <iostream>
template<typename T>
void test(T,typename T::type){ //#1
}
template<typename T,typename U>
void test(T,U){ //#2
}
int main(){
test(0,0); //we know #2 is called
}
consider above code,to call function test for arguments 0,0,the complier need to find the best match overload for these arguments and instantiate the function template,firstly,there are two function template named test,the complier deduce the template paraments from arguments for them. I want to know the instantiation or the substitution which is first performanced on the function template in the next step?whether the overload resolution is performanced after them?
when to instantiate function template
If you call the name of an overloaded function template, the compiler will try to deduce its template arguments and check its explicitly declared template arguments. If successful, it will instantiate a function template specialization, then add this specialization to the set of candidate functions used in overload resolution
when to perform substitution
Specifically, when creating a candidate set for overload resolution, some (or all) candidates of that set may be the result of instantiated templates with (potentially deduced) template arguments substituted for the corresponding template parameters. If an error occurs during the substitution of a set of arguments for any given template, the compiler removes the potential overload from the candidate set instead of stopping with a compilation error, provided the substitution error is one the C++ standard grants such treatment
I have not found the document about the order of substitution and instantiation
UPDATE:
the deduction,substitution(the sfinae is happened here) is parts of instantiation,however,except these,generate defination by substituting template arguments at the point of instantiation also a part of instantiation,when does it happen?after overload resolution or after the substitution(here is the sfinae)?
Your example doesn't show much regarding your question as there is only one viable candidate: Substitution fails for #1 as int::type is ill-formed, and thus there is only one function, #2.
On the other hand, it does mean that parameter substitution has to happen as part of the instantiation (as noted by #IgorTandetnik). And, for there to be any overloads to resolve, template instantiation has to happen before.
If you change #1 to
template <typename T>
void test(T,T){}
you would have two viable overloads, and #1 would be selected.
Edit:
On the other hand, if you change your main function to
struct {
using type = int;
int val = 0;
} x;
test(x,0);
both templates will be instantiated but overload resolution will fail as the two functions void test(anonymous struct, int) are ambiguous.
That also illustrates that the templates must be instantiated before overload resolution can take place.

Are all valid templates instantiated?

When I have multiple templates that could be instantiated, what happens?
template <typename T> void foo(T*);
template <typename T> void foo(T**);
template void foo(int**);
template <typename T> void foo(T*) { printf("called foo(T*)\n"); }
template <typename T> void foo(T**){ printf("called foo(T**)\n"); }
When we need to instantiate a foo(int**), either of the instantiations would work, one with T=int* and the other with T=int**. In practice, the object file only contains one, the T** one. On the other hand, if I put a static_assert(false) into the unused one, the compilation fails. Does that mean that it is instantiated?
It turns out that the T** is the one that I want to use in this case. But even if both were instantiated, overload resolution would pick the T** one, so this works for me either way.
Now in my actual code, I request two instantiations:
template void foo(int*);
template void foo(int**);
That instantiates foo<int>(int**) and foo<int>(int*), so I get both templates. The latter is forced, since template <typename T> foo(T**) doesn't match. But I don't understand the rules to know why I don't get foo<int*>(int**) for the former. Or both foo<int*>(int**) as well as foo<int>(int**).
And yes, I realize I could do template void foo<int*>(int**) if I needed to force it.
All this makes me realize I don't really understand what happens when the compiler sees a call that requires a template instantiation. Does it scan through templates until it finds one that works, then stop? Or does it instantiate all valid options (and then something discards the unneeded ones from the object file)?
Template argument deduction is performed to figure out what function template specialization is named by template void foo(int**);; it selects the T** one after considering partial ordering. See [temp.deduct.decl] and sections linked therein. That's roughly the same process used to pick the function template to call during overload resolution (with some minor differences).
There's no mechanism for instantiating everything that matches. If the compiler can't select a unique function template specialization, the program is simply ill-formed.
On the other hand, if I put a static_assert(false) into the unused one, the compilation fails. Does that mean that it is instantiated?
That's just [temp.res]/8 at work, as usual. Code that is ill-formed in a way that doesn't depend on a template parameter may be diagnosed immediately without instantiation.
if I put a static_assert(false) into the unused one, the compilation fails. Does that mean that it is instantiated?
No. The compiler does some basic checks on a template definition. Everything in the definition must be valid C++, but certain things which depend on a template parameter cannot be checked until an actual instantiation, when the template arguments are known. Since static_assert(false); does not depend on any template parameters, it always causes an error, and a compiler is allowed to note the error even when the template is never instantiated.
If you really want a template that should never be instantiated, the usual way is to use =delete for a function template, or leave a class template undefined.
But I don't understand the rules to know why I don't get foo<int*>(int**) for the former.
In most contexts that name a specialization of a function template, there's a rule that any template which is "more specialized" than all other viable overloads is the one that gets used. The exact definition of "more specialized" is a bit tricky, but the basic idea is that if any argument list that could be taken by a function template "A" could also be taken by a function template "B" but not vice versa, then "A" is more specialized. In your example
template <typename T> void foo(T*); // #1
template <typename T> void foo(T**); // #2
if an argument arg has type U** for any type U so that template argument deduction for template #2 for foo(arg) can succeed with T=U, we can see that template argument deduction for template #1 for foo(arg) can also succeed with T=U*. On the other hand, it's obviously possible that another argument arg2 can mean that template argument for foo(arg2) can succeed for template #1 but fail for template #2, for example if arg2 has type int*. So function template #2 is more specialized than function template #1. This means an expression like foo(arg), whenever type deduction for both succeeds (and there are no other viable overloads involved), means a use of template #2.
The same "more specialized" rule applies in your explicit instantiation
template void foo(int**);
Much like with a function call expression, the compiler will use template argument deduction to see whether the declaration you gave matches each function template. In this case both succeed, but since template #2 is more specialized, the declaration is interpreted as a specialization of #2 and not #1.
All this makes me realize I don't really understand what happens when the compiler sees a call that requires a template instantiation. Does it scan through templates until it finds one that works, then stop? Or does it instantiate all valid options (and then something discards the unneeded ones from the object file)?
The rough sequence for most uses of the name of an overloaded function template is:
Do name lookup to determine the list of function templates and functions to be considered.
For each function template in the list, attempt template argument deduction. If template argument deduction fails, or if substituting any template argument into the function type fails, ignore that template from here on. If successful, this results in a template argument for each template parameter, and one specific function type for the specialization.
Do overload resolution in mostly the same way as for non-templates, on the set of non-template functions initially looked up combined with the set of function template specializations determined above. But if two candidate functions cannot be ordered to say one is a better overload than the other just based on the parameter types and implicit conversions involved, then a non-template function beats a function template specialization, and a specialization from a more specialized function template beats a specialization from a less specialized function template.
Note that during this process, the function types but not the definitions of the function template specializations are instantiated.

What are the rules for choosing between a variadic template method and a usual template method?

I have two template operators in class:
template<class T>
size_t operator()(const T& t) const {
static_assert(boost::is_pod<T>(), "Not a POD type");
return sizeof t;
}
template<typename... T>
size_t operator()(const boost::variant<T...>& t) const
{
return boost::apply_visitor(boost::bind(*this, _1), t);
}
I pass boost::variant<some, pod, types, here> as an argument to these operators. GCC 4.8 and llvm 6.0 compile the code fine, choosing boost::variant parameterized operator. gcc 4.7 chooses const T& t parameterized operator and thus fails to compile due to static assert.
So, I have a question, what are the rules for choosing between these two?
I think gcc 4.7 must have a bug, but I don't have any proof.
The key section is in [temp.deduct.partial]:
Two sets of types are used to determine the partial ordering. For each of the templates involved there is
the original function type and the transformed function type. [ Note: The creation of the transformed type
is described in 14.5.6.2. —end note ] The deduction process uses the transformed type as the argument
template and the original type of the other template as the parameter template. This process is done twice
for each type involved in the partial ordering comparison: once using the transformed template-1 as the
argument template and template-2 as the parameter template and again using the transformed template-2
as the argument template and template-1 as the parameter template.
That's really dense, even for the C++ standard, but what it basically means is this. Take our two overloads:
template <class T> // #1
size_t operator()(const T& t) const
template <typename... T> // #2
size_t operator()(const boost::variant<T...>& t)
And we're going to basically assign some unique type(s) to each one and try to see if the other applies. So let's pick some type A for the #1, and B,C,D for #2. Does operator()(const A&) work for #2? No. Does operator()(const boost::variant<B,C,D>&) work for #1? Yes. Thus, the partial ordering rules indicate #2 is more specialized than #1.
And so, from [temp.func.order]:
The deduction process determines whether one of the templates is more specialized than the other. If
so, the more specialized template is the one chosen by the partial ordering process.
And from [over.match.best]:
[A] viable function F1 is defined to be a better function than another viable function
F2 if
— [..]
— F1 and F2 are function template specializations, and the function template for F1 is more specialized
than the template for F2 according to the partial ordering rules described in 14.5.6.2.
Thus, #2 should be chosen in any case where it applies. If GCC chooses #1, that is nonconforming behavior and is a bug.
In general the compiler just treats all deduced template instantiations as potential overloads, picking the "best viable function" (§ 13.3.3).
Indeed this means GCC 4.7 has a bug then.
See §14.8.3: Overload resolution
describes that all template instances will join in the set of candidates as any non-template declared overload:
A function template can be overloaded either by (non-template) functions of its
name or by (other) function templates of the same name. When a call to that
name is written (explicitly, or implicitly using the operator notation),
template argument deduction (14.8.2) and checking of any explicit template
arguments (14.3) are performed for each function template to find the template
argument values (if any) that can be used with that function template to
instantiate a function template specialization that can be invoked with the
call arguments. For each function template, if the argument deduction and
checking succeeds, the template- arguments (deduced and/or explicit) are used
to synthesize the declaration of a single function template specialization
which is added to the candidate functions set to be used in overload
resolution. If, for a given function template, argument deduction fails, no
such function is added to the set of candidate functions for that template. The
complete set of candidate functions includes all the synthesized declarations
and all of the non-template overloaded functions of the same name. The
synthesized declarations are treated like any other functions in the remainder
of overload resolution, except as explicitly noted in 13.3.3.
In the case of your question, the overloads end up being indistinguishable (credit: #Piotr S). In such cases "partial ordering" is applied (§14.5.6.2):
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2
Note that things can get pretty tricky, when e.g. the "open template" version took a T& instead of T const& (non const references are preferred, all else being equal).
When you had several overloads that end up having the same "rank" for overload resolution, the call is ill-formed and the compiler will diagnose an ambiguous function invocation.

Instantiation of template function overloads

I'm aware that the compiler will not instantiation unused template functions as long as they are not virtual in a class.
In a simple case, if I have two overloaded template functions both of which take the same template arguments, it seems the compiler instantiates both overloads. I guess this is required so that the compiler can perform overload resolution? Are overloads exempt from the lazy-instantiation rule for function templates? I wasn't able to find the relevant text in the standard. Here is an example:
template<typename T>
void foo(T) {zzz}
template<typename T>
void foo(T*) {}
int main()
{
int* blah;
foo(blah);
}
I would expect no compiler error if the first overload was not instantiated, however I get the error.
Live Sample
It seems as though you're expecting only one of those overloads to be instantiated because only one of them will be called, but the compiler clearly has to instantiate both of them in order to determine whether either of them can be called and, if so, which one to use.
The more formal answer is that both templates are candidates because your T can always be pointerised, so both are "used" in that sense:
[C++14: 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. 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.
[C++14: 14.7.1/10]: If a function template or a member function template specialization is used in a way that involves overload resolution, a declaration of the specialization is implicitly instantiated (14.8.3).
So, basically:
I guess this is required so that the compiler can perform overload resolution?
Correct.
Your question, however, already stems from a misconception that your first function template can be ignored: it can't be. zzz does not depend on any template parameters so SFINAE is not involved; even if SFINAE were involved, it could not help you with your invalid syntax. So, no matter what you do, that code is ill-formed:
template<typename T>
void nil() {zzz}
// g++ -c -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
// main.cpp: In function 'void nil()':
// main.cpp:2:13: error: 'zzz' was not declared in this scope
// void nil() {zzz}
// ^
(live demo)
That being said, a diagnostic is not required in this case; in particular, Microsoft Visual Studio has historically silently accepted such code:
[C++14: 14.6/8]: Knowing which names are type names allows the syntax of every template to be checked. No diagnostic shall be issued for a template for which a valid specialization can be generated. If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required. If every valid specialization of a variadic template requires an empty template parameter pack, the template is ill-formed, no diagnostic required. If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required. [..]
The same wording may also be found in C++11 and C++03, so this has always been the case. Your misconception is therefore understandable.
Incidentally, your observation regarding virtual functions is also not completely accurate:
[C++14: 14.7.1/11]: An implementation shall not implicitly instantiate a function template, a variable 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. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. The use of a template specialization in a default argument shall not cause the template to be implicitly instantiated except that a class template may be instantiated where its complete type is needed to determine the correctness of the default argument. The use of a default argument in a function call causes specializations in the default argument to be implicitly instantiated.
This is not an answer from the inner question, but it is related about the assumption of the question: "I would expect no compiler error if the first overload was not instantiated, however I get the error."
Sure? so, why this code generate a compiler error?
template<typename T>
void nil(T) {zzz}
template<typename T>
void foo(T*) {}
int main()
{
int* blah;
foo(blah);
}
because nil is not instantiated