In the C++ standard, N4618/[temp.deduct] (§14.8.2), the following example (§14.8.2/7) demonstrates how template parameter substitution is performed in lexical order:
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f(...) { }
template <class T> auto g(typename A<T>::X) -> typename T::X;
template <class T> void g(...) { }
void h() {
f<int>(0);// OK, substituting return type causes deduction to fail
g<int>(0);// error, substituting parameter type instantiates A<int>
}
I was expecting requires-clauses content to be also evaluated before declaration content. I expected that the following modification would not generate any compilation error:
template <class T> struct A { using X = typename T::X; };
template <class T> typename T::X f(typename A<T>::X);
template <class T> void f(...) { }
template <class T>
requires false
auto g(typename A<T>::X) -> typename T::X;
template <class T>
requires true
void g(...) { }
void h() {
f<int>(0);// OK, substituting return type causes deduction to fail
g<int>(0);// error, substituting parameter type instantiates A<int>
}
Actually GCC tell me there is still an error. Is it the behaviour stated in the concept TS?
Yes. See the note in N4630 [temp.deduct]/5:
The satisfaction of constraints (14.10) associated with the function
template specialization is determined during overload resolution
(13.3), and not at the point of substitution.
Related
The rules for picking which class template specialization is preferred involve rewriting the specializations into function templates and determining which function template is more specialized via the ordering rules for function templates [temp.class.order]. Consider this example, then:
#include <iostream>
template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;
template <class T, class U> struct A { };
template <class T> int foo(A<T, void_t<T>> ) { return 1; }
template <class T> int foo(A<T*, void> ) { return 2; }
int main() {
std::cout << foo(A<int*, void>{});
}
Both gcc and clang print 2 here. This makes sense with some previous examples - deducing against a non-deduced context (void against void_t<T>) is just ignored, so deducing <T, void_t<T>> against <X*, void> succeeds but deducing <T*, void> against <Y, void_t<Y>> fails in both arguments. Fine.
Now consider this generalization:
#include <iostream>
template <class T> struct voider { using type = void; };
template <class T> using void_t = typename voider<T>::type;
template <int I> struct int_ { static constexpr int value = I; };
template <class T, class U> struct A : int_<0> { };
template <class T> struct A<T, void_t<T>> : int_<1> { };
template <class T> struct A<T*, void> : int_<2> { };
int main() {
std::cout << A<int*, void>::value << '\n';
}
Both clang and gcc report this specialization as ambiguous, between 1 and 2. But why? The synthesized function templates aren't ambiguous. What's the difference between these two cases?
Clang is being GCC-compatible (and compatible with existing code that depends on both of these behaviors).
Consider [temp.deduct.type]p1:
[...] an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.
The crux of the issue is what "compatible" means here.
When partially ordering function templates, Clang merely deduces in both directions; if deduction succeeds in one direction but not the other, it assumes that means the result will be "compatible", and uses that as the ordering result.
When partially ordering class template partial specializations, however, Clang interprets "compatible" as meaning "the same". Therefore it only considers one partial specialization to be more specialized than another if substituting the deduced arguments from one of them into the other would reproduce the original partial specialization.
Changing either of these two to match the other breaks substantial amounts of real code. :(
Should it be possible to overload function template like this (only on template parameter using enable_if):
template <class T, class = std::enable_if_t<std::is_arithmetic<T>::value>>
void fn(T t)
{
}
template <class T, class = std::enable_if_t<!std::is_arithmetic<T>::value>>
void fn(T t)
{
}
if conditions in enable_if don't overlap? My MSVS compiler complains, that 'void fn(T)' : function template has already been defined. If not, what is the alternative (ideally not putting enable_if anywhere else than into template parameters)?
Default arguments don't play a role in determining uniqueness of functions. So what the compiler sees is that you're defining two functions like:
template <class T, class>
void fn(T t) { }
template <class T, class>
void fn(T t) { }
That's redefining the same function, hence the error. What you can do instead is make the enable_if itself a template non-type parameter:
template <class T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
void fn(T t) { }
template <class T, std::enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
void fn(T t) { }
And now we have different signatures, hence different functions. SFINAE will take care of removing one or the other from the overload set as expected.
I can't clearly get the grasp of what it means when one mentions that a particular function, struct or ... is SFINAE-friendly.
Would someone please explain it?
When it allows substitution failure without hard error (as static_assert).
for example
template <typename T>
void call_f(const T& t)
{
t.f();
}
The function is declared for all T, even those which don't have f, so you cannot do SFINAE on call_f<WithoutF> as the method does exist. (Demo of non compiling code).
With following change:
template <typename T>
auto call_f(const T& t) ->decltype(t.f(), void())
{
t.f();
}
The method exists only for valid T.
so you can use SFINAE as
template<typename T>
auto call_f_if_available_impl(const T& t, int) -> decltype(call_f(t))
{
call_f(t);
}
template<typename T>
auto call_f_if_available_impl(const T& t, ...)
{
// Do nothing;
}
template<typename T>
auto call_f_if_available(const T& t)
{
call_f_if_available_impl(t, 0);
}
Note the int = 0 and ... is to order the overload.
Demo
--
An other case is when the template add special parameter to apply SFINAE for specialization:
template <typename T, typename Enabler = void> struct S;
And then
// Specialization only available for T which respect the traits.
template <typename T>
struct S<T, std::enable_if_t<my_type_trait<T>::value>>
{
};
An entity is termed SFINAE-friendly if it can be used in the context of SFINAE without producing a hard error upon substitution failure. I assume you already know what SFINAE is, as that is a whole other question in itself.
In the context of C++ standardization, the term SFINAE-friendly has so far been applied to std::result_of and std::common_type. Take the following example:
template <typename T>
void foo(T x, typename std::common_type<T, int>::type y) {}
void foo(std::string x, std::string y) {}
int main()
{
foo(std::string("hello"), std::string("world"));
}
Without SFINAE-friendly common_type, this would fail to compile, because std::common_type<std::string, int>::type would produce a hard error during template argument substitution. With the introduction of SFINAE-friendly common_type (N3843) this example becomes well-formed, because std::common_type<std::string, int>::type produces a substitution failure so that overload is excluded from the viable set.
Here's a similar example with result_of:
template <typename T>
auto bar(T f) -> typename std::result_of<T()>::type { return f(); }
void bar(int n) {}
int main()
{
bar(42);
}
Without SFINAE-friendly result_of, this would fail to compile, because std::result_of<int()>::type would produce a hard error during template argument substitution. With the introduction of SFINAE-friendly result_of (N3462) this example becomes well-formed, because std::result_of<int()>::type produces a substitution failure so that overload is excluded from the viable set.
Why does the following code fail to compile?
template <typename T>
struct X
{
template <typename R>
R default_value();
};
template <typename T>
int X<T>::default_value<int>()
{
return -1;
}
it says
x.cpp:17:30: error: template-id ‘default_value<int>’ in declaration of primary template
x.cpp:17:5: error: prototype for ‘int X<T>::default_value()’ does not match any in class ‘X<T>’
x.cpp:13:7: error: candidate is: template<class T> template<class R> R X::default_value()
I also tried to do
template <typename T>
template <>
int X<T>::default_value<int>()
{
return -1;
}
but this gives me another compilation error
prog.cpp:11: error: invalid explicit specialization before '>' token
prog.cpp:11: error: enclosing class templates are not explicitly specialized
prog.cpp:12: error: template-id 'default_value<int>' for 'int X<T>::default_value()' does not match any template declaration
I also tried doing the same for structures
template <typename T>
struct X
{
template <typename R> struct default_value;
};
template <typename T>
template <>
struct X<T>::default_value<int>
{
static int get() { return -1; }
};
same issue.
How to solve that?
One cannot explicitly specialize member templates. Consider:
template <class T>
struct X
{
template <class U> struct Y;
};
...Now (imagine we could do this):
template <class T>
template <>
struct X<T>::Y<int>
{};
...For X of which T are we explicitly specializing?
What if, after the point of definition of our explicit specialization, someone does this in one compilation unit...
void foo()
{
X<int>::Y<int> xy;
}
... and then this in another...(valid code, btw).
template <>
template<>
struct X<int>::Y<int>
{};
void foo()
{
X<int>::Y<int> xy;
}
... which would imply multiple definitions of the same class???
As mentioned previously, this is treated well here
Now, considering that the default value actually depends on the type T, perhaps one can get it from the type T.
template <class T>
struct X
{
static T defaultValue(){ return T::defaultValue(); }
};
or better yet, one could change the behavior of defaultValue based on whether T has the member defaultValue.
template <typename T>
template <>
int X<T>::default_value<int>()
{
return -1;
}
should be fine. Similar topic...
In C++03, template parameter deduction does not occur in some contexts. For example:
template <typename T> struct B {};
template <typename T>
struct A
{
typedef B<T> type;
};
template <typename T>
void f(typename A<T>::type);
int main()
{
B<int> b;
f(b); // ERROR: no match
}
Here, int is not deduced for T, because a nested type such as A<T>::type is a non-deduced context.
Had I written the function like this:
template <typename T> struct B {};
template <typename T>
void f(B<T>);
int main()
{
B<int> b;
f(b);
}
everything is fine because B<T> is a deduced context.
In C++11, however, template aliases can be used to disguise a nested type in syntax similar to the second example. For example:
template <typename T> struct B {};
template <typename T>
struct A
{
typedef B<T> type;
};
template <typename T>
using C = typename A<T>::type;
template <typename T>
void f(C<T>);
int main()
{
B<int> b;
f(b);
}
Would template argument deduction work in this case? In other words, are template aliases a deduced context or a non-deduced context? Or do they inherit the deduced/non-deduced status of whatever they alias?
In other words, are template aliases a deduced context or a non-deduced context?
They are as deducible as the equivalent code without using template aliases. For example
template<typename T>
using ref = T&;
template<typename T>
void f(ref<T> r);
Now you can call f(x) and T will be deduced perfectly fine. At the definition time of f already, ref<T> is replaced by type T&. And T& is a deduced context.
In your case C<T> is replaced by typename A<T>::type, and that is a non-deduced context for T, so T cannot be deduced.
Imagine this:
template <typename T> struct Foo { typedef T type; }
template <> struct Foo<char> { typedef int type; }
template <typename T> using mytype = typename Foo<T>::type;
template <typename T> void f(mytype<T>);
Now if I want int n; f(n);, how could I decide whether I want T = int or T = char? The whole problem, which is unaffected by template aliases, is that you cannot deduce backwards to all the things that could possibly define something.
I think the relevant quote in the C++ standard is 14.5.7 [temp.alias] paragraph 2:
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template. [ Note: An alias template name is never deduced. — end note ]
There is an example following the quote which effectively spells out that it is pointless to use an alias template in a function template and hoping to deduce the template argument. This apparently applies even for situation which don't involve nested types.