All compilers I could get my hands on agree that this is fine:
template <typename Check, typename... T>
auto foo(Check, T...) -> void;
template <typename... T>
auto foo(int, T...) -> void;
int main()
{
foo(7, "");
}
However, the following code (with a leading template parameter that cannot be deduced from the function parameters) is ambiguous according to gcc:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
template <typename X, typename... T>
auto bar(int, T...) -> void;
int main()
{
bar<void>(7, ""); // ambiguous according to gcc
bar<void>(7); // just fine
}
On the other hand, clang, msvc and icc are quite happy with this.
Which compiler is right?
References to the respective sections of the standard preferred.
This is core issue 200.
The description of how the partial ordering of template functions is
determined in 14.5.6.2 [temp.func.order] paragraphs 3-5 does not make
any provision for nondeduced template parameters. For example, the
function call in the following code is ambiguous, even though one
template is "obviously" more specialized than the other:
template <class T> T f(int);
template <class T, class U> T f(U);
void g() {
f<int>(1);
}
The reason is that neither function parameter list allows template parameter T to be deduced; both deductions fail, so neither
template is considered more specialized than the other and the
function call is ambiguous.
The resolution of core issue 214, which this one was reduced to, introduced [temp.deduct.partial]/11:
In most cases, all template parameters must have values in order for deduction to succeed, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering.
Apparently GCC's implementation of this wording is buggy once packs come into play.
IMHO I believe that GCC is wrong and CLANG is correct here. I'll try to justify my claim below:
According to the standard §14.8.3/p1 Overload resolution [temp.over] (Emphasis Mine):
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 specialisation 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 synthesise the declaration of a single function template
specialisation which is added to the candidate functions set to be
used in overload resolution. If, for a given function template,
argument deduction fails or the synthesised function template
specialisation would be ill-formed, no such function is added to the
set of candidate functions for that template. The complete set of
candidate functions includes all the synthesised declarations and all
of the non-template overloaded functions of the same name. The
synthesised declarations are treated like any other functions in the
remainder of overload resolution, except as explicitly noted in
13.3.3.144
[Example:
template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}
144) The parameters of function template specializations contain
no template parameter types. The set of conversions allowed on deduced
arguments is limited, because the argument deduction process produces
function templates with parameters that either match the call
arguments exactly or differ only in ways that can be bridged by the
allowed limited conversions. Non-deduced arguments allow the full
range of conversions. Note also that 13.3.3 specifies that a
non-template function will be given preference over a template
specialisation if the two functions are otherwise equally good
candidates for an overload match.
From the above we get that explicit template arguments will be checked and if checking succeeds then will be used to synthesise a specialisation that will be added to the candidate functions for overload resolution. Thus, the fact the you specify explicitly X is irrelevant for the process.
Also from the C++ standard §13.3.3/p1.7 Best viable function [over.match.best]:
F1 and F2 are function template specialisations, and the function
template for F1 is more specialised than the template for F2
according to the partial ordering rules described in 14.5.6.2.
Now from §14.5.6.2/p3 Partial ordering of function templates [temp.func.order] we get that in partial ordering parameters packs are also into play, so no problem also here.
Now:
template <typename X, typename... T>
auto bar(int, T...) -> void;
is more specialized than:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
Therefore calling:
bar<void>(7, "");
is not ambiguous.
Based on the above I believe that this is a GCC bug.
Related
For the code below I get an ambiguous template instantiation error with gcc.
However, using Clang or Visual Studio the Code compiles fine.
A full working example of the code can be found here:
http://coliru.stacked-crooked.com/a/60ef9d73ce95e6f9
I have a class template that is build from an aggegate type
template<template<typename...> typename AggregateType, typename ...>
struct MyClass;
The aggregate type is composed from a list of base classes, for example
template<typename ... Bases>
struct Aggregate : Bases...
{ };
I have defined two specialzations of MyClass. The first specialization is the common case and reads
// specialization for two argument list for the
// aggregate type
template<template<typename...> typename AggregateType,
typename Base,
typename ... Bases1,
typename ... Bases2>
struct MyClass<
AggregateType,
AggregateType<Bases1...>,
AggregateType<Base, Bases2...>>
{
void func()
{
std::cout << "not specialized\n";
}
};
A second specialization handels the case when the the second base list has only 1 argument
// specialization for the second argument list with length 1
template<template<typename...> typename AggregateType,
typename Base,
typename ... Bases1>
struct MyClass<
AggregateType,
AggregateType<Bases1...>,
AggregateType<Base>>
{
void func()
{
std::cout << "specialized\n";
}
};
Using MyClass with a second argument list of length 1, I expected the compiler to choose the second specialization of MyClass, since it is the more specilized template
class Foo {};
class Bar {};
int main()
{
// this should give the not specialized class
using NotSpecialized = MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo, Bar>>;
NotSpecialized ns;
ns.func();
// this should give the specialized class
using Specialized = MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo>>;
Specialized s;
s.func();
}
While the code works fine with Clang, gcc gives an ambiguous template instantiation error. How can I circumvent this error and still use gcc?
If I remove the AggregateType template argument, the code also works with gcc, see http://coliru.stacked-crooked.com/a/c1f6edd5fab7df4d
(All ISO Standard references below refer to N4659: March 2017 post-Kona working draft/C++17 DIS, and all example program results are consistent over GCC and Clang for C++11, C++14 and C++17)
I believe GCC is wrong here, but I haven't been able to find a corresponding (open) GCC bug report.
[temp.class.order]/1 covers the partial ordering of class template specializations [emphasis mine]:
For two class template partial specializations, the first is more
specialized than the second if, given the following rewrite to two
function templates, the first function template is more specialized
than the second according to the ordering rules for function
templates:
(1.1) Each of the two function templates has the same template parameters as the corresponding partial specialization.
(1.2) Each function template has a single function parameter whose type is a class template specialization where the template arguments
are the corresponding template parameters from the function template
for each template argument in the template-argument-list of the
simple-template-id of the partial specialization.
Thus, for analyzing ordering, we re-write the class template specializations as function templates, as per above:
// G)
template<template<typename...> typename AggregateType,
typename Base,
typename... Bases1,
typename... Bases2>
void f(MyClass<AggregateType,
AggregateType<Bases1...>,
AggregateType<Base, Bases2...>>);
// F)
template<template<typename...> typename AggregateType,
typename Base,
typename... Bases1>
void f(MyClass<AggregateType, AggregateType<Bases1...>, AggregateType<Base>>);
The partial ordering of the G and F overloads of f is governed by [temp.func.order]/2, [temp.func.order]/3 and [temp.func.order]/4 [emphasis mine]:
[temp.func.order]/2
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.
[temp.func.order]/3
To produce the transformed template, for each type, non-type, or
template template parameter (including template parameter packs
thereof) synthesize a unique type, value, or class template
respectively and substitute it for each occurrence of that parameter
in the function type of the template. [...]
[temp.func.order]/4
Using the transformed function template's function type, perform type deduction against the other template as described in [temp.deduct.partial]. [...]
Thus, to produce the transformed template for the two f overloads above, specifically considering the template template parameter AggregateType (as used in both overloads) and the instantiation of these overloads with the particular class template Aggregate and classes Foo and Bar,
template<typename ... Bases>
struct Aggregate : Bases...
{ };
class Foo {};
class Bar {};
used as arguments for the template template parameter and template parameters, respectively, we may without loss of generality consider the following (partially) transformed function templates as argument templates when continuing the analysis of the partial ordering of the original class templates:
// G-transformed (argument template>
template<typename... Bases2>
void f(MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo, Bases2...>>);
// F-transformed (argument template>
void f(MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo>>);
From [temp.deduct.partial]/2, [temp.deduct.partial]/10 and [temp.deduct.partial]/11 [extracts, emphasis mine]:
[temp.deduct.partial]/2
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. [...] The deduction process uses the
transformed type as the argument template and the original type of
the other template as the parameter template.
[temp.deduct.partial]/10
Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering, the type from F is at least as specialized as the type from G. F is more specialized than G if F is at least as specialized as G and G is not at least as specialized as F.
[temp.deduct.partial]/11
If, after considering the above, function template F is at least as specialized as function template G and vice-versa, and if G has a trailing parameter pack for which F does not have a corresponding parameter, and if F does not have a trailing parameter pack, then F is more specialized than G.
it follows that that F is at least as specialized as G (/10), and moreover that F is more specialized than G due to the (additional) trailing parameter pack Bases2 that is present in G but not in F (/11). It may even be possible to directly apply the second part of [temp.deduct.partial]/10 to argue that F is more specialized than G as Aggregate<Foo> is more specialized than Aggregate<Foo, Bases2...>>.
Either way, either per /10 and /11, or per /10 alone, the Specialized alias
using Specialized = MyClass<Aggregate, Aggregate<Foo, Bar>, Aggregate<Foo>>;
refers non-ambigiously to the "second specialization" (from OPs post) of MyClass, specifically the specialization that was re-written to the F function template above, as this class template specialization is more specialized than the "first specialization" (the one with the additional Bases2 variadic template parameter pack).
I've stumbled over "Why is the template argument deduction not working here?" recently and the answers can be summed up to "It's a nondeduced context".
Specifically, the first one says it's such a thing and then redirects to the standard for "details", while the second one quotes the standard, which is cryptic to say the least.
Can someone please explain to mere mortals, like myself, what a nondeduced context is, when does it occur, and why does it occur?
Deduction refers to the process of determining the type of a template parameter from a given argument. It applies to function templates, auto, and a few other cases (e.g. partial specialization). For example, consider:
template <typename T> void f(std::vector<T>);
Now if you say f(x), where you declared std::vector<int> x;, then T is deduced as int, and you get the specialization f<int>.
In order for deduction to work, the template parameter type that is to be deduced has to appear in a deducible context. In this example, the function parameter of f is such a deducible context. That is, an argument in the function call expression allows us to determine what the template parameter T should be in order for the call expression to be valid.
However, there are also non-deduced contexts, where no deduction is possible. The canonical example is "a template parameter that appears to the left of a :::
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
In this function template, the T in the function parameter list is in a non-deduced context. Thus you cannot say g(x) and deduce T. The reason for this is that there is no "backwards correspondence" between arbitrary types and members Foo<T>::type. For example, you could have specializations:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
If you call g(double{}) there are two possible answers for T, and if you call g(int{}) there is no answer. In general, there is no relationship between class template parameters and class members, so you cannot perform any sensible argument deduction.
Occasionally it is useful to inhibit argument deduction explicitly. This is for example the case for std::forward. Another example is when you have conversions from Foo<U> to Foo<T>, say, or other conversions (think std::string and char const *). Now suppose you have a free function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
If you call binary_function(t, u), then the deduction may be ambiguous and thus fail. But it is reasonable to deduce only one argument and not deduce the other, thus permitting implicit conversions. Now an explicitly non-deduced context is needed, for example like this:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(You may have experienced such deduction problems with something like std::min(1U, 2L).)
I've stumbled over "Why is the template argument deduction not working here?" recently and the answers can be summed up to "It's a nondeduced context".
Specifically, the first one says it's such a thing and then redirects to the standard for "details", while the second one quotes the standard, which is cryptic to say the least.
Can someone please explain to mere mortals, like myself, what a nondeduced context is, when does it occur, and why does it occur?
Deduction refers to the process of determining the type of a template parameter from a given argument. It applies to function templates, auto, and a few other cases (e.g. partial specialization). For example, consider:
template <typename T> void f(std::vector<T>);
Now if you say f(x), where you declared std::vector<int> x;, then T is deduced as int, and you get the specialization f<int>.
In order for deduction to work, the template parameter type that is to be deduced has to appear in a deducible context. In this example, the function parameter of f is such a deducible context. That is, an argument in the function call expression allows us to determine what the template parameter T should be in order for the call expression to be valid.
However, there are also non-deduced contexts, where no deduction is possible. The canonical example is "a template parameter that appears to the left of a :::
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
In this function template, the T in the function parameter list is in a non-deduced context. Thus you cannot say g(x) and deduce T. The reason for this is that there is no "backwards correspondence" between arbitrary types and members Foo<T>::type. For example, you could have specializations:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
If you call g(double{}) there are two possible answers for T, and if you call g(int{}) there is no answer. In general, there is no relationship between class template parameters and class members, so you cannot perform any sensible argument deduction.
Occasionally it is useful to inhibit argument deduction explicitly. This is for example the case for std::forward. Another example is when you have conversions from Foo<U> to Foo<T>, say, or other conversions (think std::string and char const *). Now suppose you have a free function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
If you call binary_function(t, u), then the deduction may be ambiguous and thus fail. But it is reasonable to deduce only one argument and not deduce the other, thus permitting implicit conversions. Now an explicitly non-deduced context is needed, for example like this:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(You may have experienced such deduction problems with something like std::min(1U, 2L).)
I'm experimenting with resolving the address of an overloaded function (bar) in the context of another function's parameter (foo1/foo2).
struct Baz {};
int bar() { return 0; }
float bar(int) { return 0.0f; }
void bar(Baz *) {}
void foo1(void (&)(Baz *)) {}
template <class T, class D>
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
int main() {
foo1(bar); // Works
foo2<Baz>(bar); // Fails
}
There's no trouble with foo1, which specifies bar's type explicitly.
However, foo2, which disable itself via SFINAE for all but one version of bar, fails to compile with the following message :
main.cpp:19:5: fatal error: no matching function for call to 'foo2'
foo2<Baz>(bar); // Fails
^~~~~~~~~
main.cpp:15:6: note: candidate template ignored: couldn't infer template argument 'D'
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
^
1 error generated.
It is my understanding that C++ cannot resolve the overloaded function's address and perform template argument deduction at the same time.
Is that the cause ? Is there a way to make foo2<Baz>(bar); (or something similar) compile ?
As mentioned in the comments, [14.8.2.1/6] (working draft, deducing template arguments from a function call) rules in this case (emphasis mine):
When P is a function type, function pointer type, or pointer to member function type:
If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.
SFINAE takes its part to the game once the deduction is over, so it doesn't help to work around the standard's rules.
For further details, you can see the examples at the end of the bullet linked above.
About your last question:
Is there a way to make foo2<Baz>(bar); (or something similar) compile ?
Two possible alternatives:
If you don't want to modify the definition of foo2, you can invoke it as:
foo2<Baz>(static_cast<void(*)(Baz *)>(bar));
This way you explicitly pick a function out of the overload set.
If modifying foo2 is allowed, you can rewrite it as:
template <class T, class R>
auto foo2(R(*d)(T*)) {}
It's more or less what you had before, no decltype in this case and a return type you can freely ignore.
Actually you don't need to use any SFINAE'd function to do that, deduction is enough.
In this case foo2<Baz>(bar); is correctly resolved.
Some kind of the general answer is here: Expression SFINAE to overload on type of passed function pointer
For the practical case, there's no need to use type traits or decltype() - the good old overload resolution will select the most appropriate function for you and break it into 'arguments' and 'return type'. Just enumerate all possible calling conventions
// Common functions
template <class T, typename R> void foo2(R(*)(T*)) {}
// Different calling conventions
#ifdef _W64
template <class T, typename R> void foo2(R(__vectorcall *)(T*)) {}
#else
template <class T, typename R> void foo2(R(__stdcall *)(T*)) {}
#endif
// Lambdas
template <class T, class D>
auto foo2(const D &d) -> void_t<decltype(d(std::declval<T*>()))> {}
It could be useful to wrap them in a templated structure
template<typename... T>
struct Foo2 {
// Common functions
template <typename R> static void foo2(R(*)(T*...)) {}
...
};
Zoo2<Baz>::foo2(bar);
Although, it will require more code for member functions as they have modifiers (const, volatile, &&)
Consider the following code:
#include <iostream>
#include <type_traits>
// Variadic version
template<class... Variadic>
void f(const Variadic&... variadic)
{
std::cout<<"variadic"<<std::endl;
}
// Single version
template<class Single, class = typename std::enable_if<std::is_fundamental<Single>::value>::type>
void f(const Single& single)
{
std::cout<<"single"<<std::endl;
}
// Main
int main()
{
f(); // variadic
f(42); // single : why?
f(std::string()); // variadic
f(42, 42); // variadic
return 0;
}
I do not understand why the line marked "single" compiles well (under g++ 4.6.3) and does not produce an overload resolution problem. Does the c++11 standard say that a template function with a fixed number of parameters is prefered over a variadic function that could have the same signature ?
It is really quite simple (two live examples, gcc and clang)
template<class...T> void foo(T&&...) {std::cout << "...T\n";}
template<class T> void foo(T&&) {std::cout << "T\n";}
int main() {
foo(3);
}
Overloads not taking ... seem to be preferred when the choice is an explicit template parameter.
The class=std::enable_if_t does not change this.
So both your functions f are candidates, then the compiler prefers the one without variardics.
14.8.2.4 Deducing template arguments during partial ordering [temp.deduct.partial]
/8:
If A was transformed from a function parameter pack and P is not a parameter pack, type deduction fails. Otherwise, using the resulting types P and A, the deduction is then done as described in 14.8.2.5. If P is a function parameter pack, the type A of each remaining parameter type of the argument template is compared with the type P of the declarator-id
of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template. [
Example:
template<class... Args> void f(Args... args); // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2> void f(T1 a1, T2 a2); // #3
f(); // calls #1
f(1, 2, 3); // calls #2
f(1, 2); // calls #3; non-variadic template #3 is more
// specialized than the variadic templates #1 and #
In particular, the f(1,2) example.
All the enable_if_t clause does is remove the one-argument version from consideration when you pass a std::string as T.
Due to the use of the second, enable_if, template parameter in the 'single' version, the compiler considers that version to be a more-specialized template for use with the types for which it is enabled.
It is considered more specialized because there are types where the variadic template can be instantiated, but the 'single' can't.
The general rule is that a more specialized template trumps a less specialized template in overload resolution.