Template type deduction - c++

I have come across class = std::enbale_if<condition, type>::type couple times in template parameter list, I know what std::enable_if<B,T>::type does but not sure what class = does ? I mean I know class type_name = type but why there is no type name in class = ? when would I use it ?
Edit: This example from here
template <class T, class U, class = typename enable_if
<is_lvalue_reference<T>::value ? is_lvalue_reference<U>::value : true>::type>
inline T&& forward(U&& u)
{
return static_cast<T&&>(u);
}

This is SFINAE (substitution failure is not an error). Below are two examples, where constraints are put on struct and class to disallow instantiations with types that would not be correct.
but not sure what class = does ? I mean I know class type_name = type but why there is no type name in class = ? when would I use it ?
This is an unnamed template parameter type, you could give it a name but its not needed as this parameter is only used during overload resoultion (to remove non valid candidates). Actually giving it a name might show warnings.
http://coliru.stacked-crooked.com/a/25162a3eb107943f
// Allow only T to be floating type (!! actually static_assert would be preferred here)
template<class T,
class = typename std::enable_if<std::is_floating_point<T>::value>::type>
struct foo {
};
template <class T,
class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even(T i) {return !bool(i%2);}
int main()
{
// foo<int> f; //error
foo<float> f; //ok
//is_even(1.1); //error
is_even(1); //ok
return 0;
}
[edit]
I must say above examples are not the best, and using static_assert would be recomended as it allows to generate informative error messages. SFINAE should not be used for parameter validation but rather for selecting another implementation depending on provided types.

It's an unnamed template type parameter. Just like you can leave out the variable name in unused function parameters, you can leave out the parameter name in unreferenced template parameters.
In the specific case of std::enable_if<...>::type, this is used solely for SFINAE purposes. Specifically, if the boolean in the enable_if is false, template parameter deduction will fail.

Related

Overloading operator+() in global scope, for a template class inside a template class [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).)

Defaulted Template in Template Function Requires Empty Angle Brackets <>

gcc 11.2 can't seem to compile this:
template <typename T = int>
struct Test {};
template <typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test>(t);
}
but has no problem with
template <typename T = int>
struct Test {};
template <typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test<>>(t);
}
Is this a compiler bug?
This question seems to suggest it should work.
GCC is right. An empty template argument list, <> for a function template is allowed to be omitted ([temp.arg.explicit]/4). In other cases, the template argument list is generally required in order to name a particular specialization of a template, even if it is empty. See the grammar for simple-template-id, [temp.names]/1.
As a limited exception to the rule, if the name of a class template without a template argument list appears in a context where a concrete type is required, it is known as a "placeholder for a deduced class type" and this is only allowed in specific contexts listed in [dcl.type.class.deduct]. The most common one is a variable declaration like std::pair p("foo", 1) where the compiler will deduce std::pair<const char*, int> in C++17 and later.
In your code, you are trying to refer to a particular specialization of class template Test, without specifying the template argument list, and not in a context where the template arguments can be deduced. Therefore, it's not allowed.
The new Class template argument deduction (CTAD) (since C++17) is applied to declarations. The expression foo<Test<>>(t); is not a declaration, it is a template function call.
In your first code snippet, you specify a class template (Test) as a template parameter to foo and not a type (like an instance of a class template). You would need a function that takes a template template parameter to handle that.
Example:
#include <type_traits>
template<template<class> class T, class U> // T = Test, U = deduced to int
void foo(T<U>& bar) {
std::cout << std::is_same<T<U>, Test<int>>::value << '\n'; // true
}
int main() {
Test t;
foo<Test>(t); // now ok
}
In your second snippet, foo<Test<>>(t); instantiates foo<Test<int>>(Test<int>&); since <> makes the template instantiation use the default type for the template parameter, which is int.

Why double colon in template argument works?

While answering one of SO questions I came across code like this:
template<class T, class... Ts> void foo();
template <class T, class T::value_type>
void foo() { }
It was presented as code specializing foo template function, which is not right, but that is not my issue here. I would like to know why does compiler allow construcion like this: class T::value_type in the template parameter. I mean, it is pretty clearly wrong, I cannot come up with any situation that scope operator may be part of the argument name (either template or function). And so I have two qestions:
Does standard allow it or is it an overlook in compilers?
If standard allows it, why is it so? Are there any use cases?
As mentioned in the comments, it's an elaborated type specifier. Best explained with an example:
int main() {
struct foo {}; // ok
int foo = 0; // ok
int test = foo; // ok, refers to variable 'foo'
foo a; // error, 'foo' refers to variable
struct foo b; // ok, 'struct' means that name lookup searches for classes only
}
In essence, you can think of them (struct/class, enum) as a more restricted typename, as they only allow classes or enums respectively. Also do note that typename is allowed in your original example!
template<class T, class... Ts> void foo();
template <class T, typename T::value_type> // Ok, value_type needs to be a type
// ^^^^^^^^^^^^^^^^^^^^^^^ it's a non-type template parameter
void foo() { }
It is needed when you have a type and a variable with the same name, or to specify what the thing is when you have a dependent name (i.e. in class T::value_type, value_type is a class, without the class before, it would have been a value. Normally, a typename is used.)
I cannot come up with any situation that scope operator may be part of the argument name
Your only thinking of type template parameters here; non-type template parameters can very well use a scope operator to name the type.

C++ template class = typename

what template <class = typename T::type> means? Can you refer me to some blog, specification describing this?
The question originaly came from explanation of sfinae on cpp reference
template <typename A>
struct B { typedef typename A::type type; };
template <
class T,
class = typename T::type, // SFINAE failure if T has no member type
class U = typename B<T>::type // hard error if T has no member type
// (guaranteed to not occur as of C++14)
> void foo (int);
First, I'll explain typename T::type. This is simply the access of a member type. Here's an example of accessing a member type:
struct foo {
using bar = int;
};
int main() {
foo::bar var{};
// var has type int
}
So why the typename? It simply means we want to access a type. Since we are in a template and T is an unknown type, and foo::bar could also mean accessing a static variable. To disambiguate, we denote that we effectively want to access a type by explicitly typing typename.
Okay, now what does the class = means?
The class = means the same thing as typename =. When declaring template type parameters, we introduce then using class or typename:
template<typename A, typename B>
struct baz {};
But as any parameters in C++, the name is optional. I could have wrote this and the following is completely equivalent:
template<typename, typename>
struct baz {};
Also, you know in function parameters, we can specify default values? Like that:
void func(int a, int b = 42);
int main () {
func(10); // parameter b value is 42
// We are using default value
}
We can also omit parameter names:
void func(int, int = 42);
Just like function parameters, template parameters can have it's name omitted, and can have a default value.
template<typename, typename = float>
struct baz {};
baz<int> b; // second parameter is float
Putting it all together
Now we have this declaration:
template <
class T,
class = typename T::type, // SFINAE failure if T has no member type
class U = typename B<T>::type // hard error if T has no member type
// (guaranteed to not occur as of C++14)
> void foo (int);
Here we declare a function that takes an int as parameter, and has three template parameter.
The fist parameter is a simple named parameter. The name is T and it's a type template parameter. The second is also a type parameters, but it has no name. However, it has a default value of T::type, which is a member type of T. We are explicitly telling the compiler that T::type must be a member type of T by specifying typename. The third parameter is similar to the second.
This is where SFINAE kicks in: when a default parameter is used, but T::type as as a member type don't exist, how can you assign the second template parameter to that? We can't. If T::type don't exists, we cannot assign the second template parameter. But instead of making it an error, the compiler will simply try another function, because there is a chance another function would be callable.
This is quite similar to simple overloading. You have the f function. It takes a float parameter, an another overload that takes a std::string. Imagine you call f(9.4f). Does the compiler choke because a std::string is not constructible from a float? No! The compiler ain't stupid. It will try another overload, and will find the float version and call it. In SFINAE a similar analogy can be made. The compiler won't stop because there's some overload somewhere that needs an undefined type in a template parameter. It will try another overload.

Partial template specialization type collapsing rules

Sorry for the lack of a better title.
While trying to implement my own version of std::move and understanding how easy it was, I'm still confused by how C++ treats partial template specializations. I know how they work, but there's a sort of rule that I found weird and I would like to know the reasoning behind it.
template <typename T>
struct BaseType {
using Type = T;
};
template <typename T>
struct BaseType<T *> {
using Type = T;
};
template <typename T>
struct BaseType<T &> {
using Type = T;
};
using int_ptr = int *;
using int_ref = int &;
// A and B are now both of type int
BaseType<int_ptr>::Type A = 5;
BaseType<int_ref>::Type B = 5;
If there wasn't no partial specializations of RemoveReference, T would always be T: if I gave a int & it would still be a int & throughout the whole template.
However, the partial specialized templates seem to collapse references and pointers: if I gave a int & or a int * and if those types match with the ones from the specialized template, T would just be int.
This feature is extremely awesome and useful, however I'm curious and I would like to know the official reasoning / rules behind this not so obvious quirk.
If your template pattern matches T& to int&, then T& is int&, which implies T is int.
The type T in the specialization only related to the T in the primary template by the fact it was used to pattern match the first argument.
It may confuse you less to replace T with X or U in the specializations. Reusing variable names can be confusing.
template <typename T>
struct RemoveReference {
using Type = T;
};
template <typename X>
struct RemoveReference<X &> {
using Type = X;
};
and X& matches T. If X& is T, and T ia int&, then X is int.
Why does the standard say this?
Suppose we look af a different template specialization:
template<class T>
struct Bob;
template<class E, class A>
struct Bob<std::vector<E,A>>{
// what should E and A be here?
};
Partial specializations act a lot like function templates: so much so, in fact, that overloading function templates is often mistaken for partial specialization of them (which is not allowed). Given
template<class T>
void value_assign(T *t) { *t=T(); }
then obviously T must be the version of the argument type without the (outermost) pointer status, because we need that type to compute the value to assign through the pointer. We of course don't typically write value_assign<int>(&i); to call a function of this type, because the arguments can be deduced.
In this case:
template<class T,class U>
void accept_pair(std::pair<T,U>);
note that the number of template parameters is greater than the number of types "supplied" as input (that is, than the number of parameter types used for deduction): complicated types can provide "more than one type's worth" of information.
All of this looks very different from class templates, where the types must be given explicitly (only sometimes true as of C++17) and they are used verbatim in the template (as you said).
But consider the partial specializations again:
template<class>
struct A; // undefined
template<class T>
struct A<T*> { /* ... */ }; // #1
template<class T,class U>
struct A<std::pair<T,U>> { /* ... */ }; // #2
These are completely isomorphic to the (unrelated) function templates value_assign and accept_pair respectively. We do have to write, for example, A<int*> to use #1; but this is simply analogous to calling value_assign(&i): in particular, the template arguments are still deduced, only this time from the explicitly-specified type int* rather than from the type of the expression &i. (Because even supplying explicit template arguments requires deduction, a partial specialization must support deducing its template arguments.)
#2 again illustrates the idea that the number of types is not conserved in this process: this should help break the false impression that "the template parameter" should continue to refer to "the type supplied". As such, partial specializations do not merely claim a (generally unbounded) set of template arguments: they interpret them.
Yet another similarity: the choice among multiple partial specializations of the same class template is exactly the same as that for discarding less-specific function templates when they are overloaded. (However, since overload resolution does not occur in the partial specialization case, this process must get rid of all but one candidate there.)