SFINAE with operator<< [duplicate] - c++

I created two simple functions which get template parameters and an empty struct defining a type:
//S<T>::type results in T&
template <class T>
struct S
{
typedef typename T& type;
};
//Example 1: get one parameter by reference and return it by value
template <class A>
A
temp(typename S<A>::type a1)
{
return a1;
}
//Example 2: get two parameters by reference, perform the sum and return it
template <class A, class B>
B
temp2(typename S<A>::type a1, B a2)//typename struct S<B>::type a2)
{
return a1 + a2;
}
The argument type is applied to the struct S to get the reference. I call them with some integer values but the compiler is unable to deduce the arguments:
int main()
{
char c=6;
int d=7;
int res = temp(c);
int res2 = temp2(d,7);
}
Error 1 error C2783: 'A
temp(S::type)' : could not deduce
template argument for 'A'
Error 2 error C2783: 'B
temp2(S::type,B)' : could not
deduce template argument for 'A'
Why is this happening? Is it that hard to see that the template arguments are char and int values?

Just as first note, typename name is used when you mention a dependent name. So you don't need it here.
template <class T>
struct S
{
typedef T& type;
};
Regarding the template instantiation, the problem is that typename S<A>::type characterizes a nondeduced context for A. When a template parameter is used only in a nondeduced context (the case for A in your functions) it's not taken into consideration for template argument deduction. The details are at section 14.8.2.4 of the C++ Standard (2003).
To make your call work, you need to explicitly specify the type:
temp<char>(c);

It is looks like nondeduced context. According to C++ Standard 14.8.2.4/4:
The nondeduced contexts are:
The nested-name-specifier of a type that was specified using a qualified-id.
A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.
When a type name is specified in a way that includes a nondeduced context, all of the types that comprise that type name are also nondeduced. However, a compound type can include both deduced and nondeduced types. [Example: If a type is specified as A<T>::B<T2>, both T and T2 are nondeduced. Likewise, if a type is specified as A<I+J>::X<T>, I, J, and T are nondeduced. If a type is specified as void f(typename A<T>::B, A<T>), the T in A<T>::B is nondeduced but the T in A<T> is deduced. ]

Deduction works in the forward direction:
template <class T> void f(T);
f(2); // can deduce int from T
Why is this happening?
It doesn't work in the backwards direction (your example):
template <class A> void g(typename S<A>::type);
Is it that hard to see that the template arguments are char and int values?
Template deduction can do some magical (Turing-complete) things, but I don't think this is one of them.
You might use something like (untested):
template <class SA> void h(SA a1)
{
STATIC_ASSERT(same_type<SA, S<A>::type>::value);
typedef typename SA::type A;
...
}
Using your favorite static assert library (Boost has two).

Related

C++ - Template parameter deduction failed from subclass [duplicate]

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).)

Template Template function not deducing arguments as expected [duplicate]

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).)

Template arguments can't be omitted when specializing this function template

In C++, Explicit specializations of function templates is like:
template<typename T> return_type fun_name();
template<> return_type fun_name<int>(){/* blabla */}
The <int> in the above example is called template argument. Sometimes <int> can be ommitted because compiler can do Template Argument Deduction
But I can't find out why Template Argument Deduction failed in the following example:
//-------------failed case-------------
template <typename T>
struct deduce{
typedef T* type;
};
template <typename T>
typename deduce<T>::type fun1();
template <>
typename deduce<float>::type fun1<float>() //error if no "<float>" after fun1
{
}
//------------now the "Template Argument Deduction" works------------
template <typename T>
struct some_struct{
T* p;
};
template <typename T>
some_struct<T> fun2();
template <>
some_struct<float> fun2() // no error even if no "<float>" after fun2
{
}
If no <float> is after fun1, The error message is:
error: template-id ‘fun1<>’ for ‘float* fun1()’ does not match any template declaration
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
Let me provide an example of why non-deduced contexts are non-deduced. Template deduction is basically trying to match on the input. If I had:
template <class T> void foo(T );
and I call foo(4), that's easy. T=int. If I call foo('x'), T=char. These are easy substitutions to make. If T is nested somewhere in the type, like:
template <class T> void bar(std::vector<T> );
that's still totally doable. If I call it with a std::vector<std::vector<float>>, T=std::vector<float>. Still no problem.
Now consider this one:
template <class T> void baz(typename X<T>::type );
baz(4);
What's T? In all our previous cases, there was one obvious choice for T that was deduced directly from the argument passed to the function template. But here, that's not the case. We have an extra layer of indirection - we need to deduce a T to make a type X<T> whose member typedef type is int. How do we find such a thing?
Now let's say we had this:
template <class T> struct X { using type = T; };
Ok now it's easy right? T=int? Well, not so fast. For the primary template, that would work in this case. But what if there was also this specialization:
template <class T> struct X<T*> { using type = T; };
(that is, X is std::remove_pointer). Now we're in a situation where T=int works... but T=int* also works. And maybe there's some other type out there that also works for int. How do you pick the right one?
This problem - picking a template parameter in the nested-name specifier of qualified-id - is really hard and has no obvious path forward. So the compiler just won't take a path forward. It's a non-deduced context. T will never be deduced in the call to baz, the caller has to provide it:
baz<int>(4); // ahhhhh, ok, you wanted X<int>::type
Back to your question. some_struct<T> is a deduced-context, but typename deduce<T>::type is a non-deduced context. I hope it's clear now why the former works but the latter doesn't.
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
It has nothing to do with typename, the point is that deduce<T>::... is a nested-name-specifier; which belongs to Non-deduced contexts:
(emphasis mine)
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
So, for
template <>
typename deduce<float>::type fun1()
deduce<float>::type (i.e. float*) will be used to deduce type T for deduce<T>::type, but T won't be deduced, template argument deduction fails. You have to explicitly specify it as float.

What is a nondeduced context?

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).)

Why is the template argument deduction not working here?

I created two simple functions which get template parameters and an empty struct defining a type:
//S<T>::type results in T&
template <class T>
struct S
{
typedef typename T& type;
};
//Example 1: get one parameter by reference and return it by value
template <class A>
A
temp(typename S<A>::type a1)
{
return a1;
}
//Example 2: get two parameters by reference, perform the sum and return it
template <class A, class B>
B
temp2(typename S<A>::type a1, B a2)//typename struct S<B>::type a2)
{
return a1 + a2;
}
The argument type is applied to the struct S to get the reference. I call them with some integer values but the compiler is unable to deduce the arguments:
int main()
{
char c=6;
int d=7;
int res = temp(c);
int res2 = temp2(d,7);
}
Error 1 error C2783: 'A
temp(S::type)' : could not deduce
template argument for 'A'
Error 2 error C2783: 'B
temp2(S::type,B)' : could not
deduce template argument for 'A'
Why is this happening? Is it that hard to see that the template arguments are char and int values?
Just as first note, typename name is used when you mention a dependent name. So you don't need it here.
template <class T>
struct S
{
typedef T& type;
};
Regarding the template instantiation, the problem is that typename S<A>::type characterizes a nondeduced context for A. When a template parameter is used only in a nondeduced context (the case for A in your functions) it's not taken into consideration for template argument deduction. The details are at section 14.8.2.4 of the C++ Standard (2003).
To make your call work, you need to explicitly specify the type:
temp<char>(c);
It is looks like nondeduced context. According to C++ Standard 14.8.2.4/4:
The nondeduced contexts are:
The nested-name-specifier of a type that was specified using a qualified-id.
A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.
When a type name is specified in a way that includes a nondeduced context, all of the types that comprise that type name are also nondeduced. However, a compound type can include both deduced and nondeduced types. [Example: If a type is specified as A<T>::B<T2>, both T and T2 are nondeduced. Likewise, if a type is specified as A<I+J>::X<T>, I, J, and T are nondeduced. If a type is specified as void f(typename A<T>::B, A<T>), the T in A<T>::B is nondeduced but the T in A<T> is deduced. ]
Deduction works in the forward direction:
template <class T> void f(T);
f(2); // can deduce int from T
Why is this happening?
It doesn't work in the backwards direction (your example):
template <class A> void g(typename S<A>::type);
Is it that hard to see that the template arguments are char and int values?
Template deduction can do some magical (Turing-complete) things, but I don't think this is one of them.
You might use something like (untested):
template <class SA> void h(SA a1)
{
STATIC_ASSERT(same_type<SA, S<A>::type>::value);
typedef typename SA::type A;
...
}
Using your favorite static assert library (Boost has two).