Template argument deduction for class templates and multiple parameters packs - c++

In C++17 template arguments for a class template will be deduced more or less as it happens nowadays for a function template.
Here is the relevant paper.
As an example from the above mentioned paper:
template<class ... Ts> struct X { X(Ts...) };
X x1{1}; // OK X<int>
X x11; // OK X<>
Function templates have another interesting feature when deduction happens.
Consider the following code:
template<typename... U, typename... T>
auto func(T&&...) {}
// ...
// U is int, char - T is int, double
func<int, char>(0, .0);
We can have two parameters packs as long as deduction helps to discriminate between them.
No need to wrap them within a tuple or some other structure.
Will it be possible to do the same with class templates?
As an example:
template<typename... U, typename... T>
struct S {
S(T&&...) {}
};
// ...
// U is int, char - T is int, double
S<int, char> s{0, .0};
The paper contains the example below:
template<class ... Ts> struct X { X(Ts...) };
X<int> x3{1, 'a', "bc"}; // OK X<int,char,const char*>
Anyway, it isn't exactly the same thing and I'm not sure if it will be allowed or not.

This:
template<typename... U, typename... T>
struct S { ... };
is just ill-formed per [temp.param]:
If a template-parameter of a primary class template, primary variable template, or alias template is a template parameter pack, it shall be the last template-parameter.
This case:
template<class ... Ts> struct X { X(Ts...) };
X<int> x3{1, 'a', "bc"}; // OK X<int,char,const char*>
is problematic since X<int> is already a valid type. This part of the paper was dropped in Oulu, though it's possible some proposal in the future will make it possible to indicate that some of the class template parameters should be deduced but others should be specified:
X<string, ???> x3{"a", 1, "b"}; // X<string, int, const char*>.
where ??? is some series of tokens that makes intent clear.

Related

What this template syntax "typename = T" mean?

Sometimes I see syntax like this.
template<typename T,typename = int>
int foo(){
//...
}
what part typename = int mean?
Where it can be used?
foo has two template arguments. The first is called T and the second is unnamed and defaults to int.
In your piece of code alone there is no reason to use the second argument. Unnamed template arguments often come up with SFINAE. An example from cppreference:
// primary template handles non-referenceable types:
template<class T, class = void>
struct reference_traits {
using add_lref = T;
using add_rref = T;
};
// specialization recognizes referenceable types:
template<class T>
struct reference_traits<T, std::void_t<T&>> {
using add_lref = T&;
using add_rref = T&&;
};
template<class T>
using add_lvalue_reference_t = typename reference_traits<T>::add_lref;
template<class T>
using add_rvalue_reference_t = typename reference_traits<T>::add_rref;
The only reason for the primary template to have a second argument is that it can be specialized. When possible the more specialized specialization is instantiatied. If this fails (because T& is not valid) then "substitution failure is not an error" (SFINAE) kicks in and the primary template is instantiated instead.
A simpler example of unnamed argument is when you want a template argument merely as a tag to distinguish different instantiations:
template<typename = int>
struct bar {
// ...
};
Even if the implementation of bar does not depend on the template argument you might want to have bar<double> and bar<std::string> be two distinct types.
this is rarely used ...
but this is the default value for the typename but you don't need it here because the compiler itself can overload the function automatically and get the right type for the right arguments you passed !
also it type for what typename ? it's not makes sense here !
it used when you are using nested template ...
I found out in the original reference for C++ :
The template parameter lists of template template parameters can have
their own default arguments, which are only in effect where the
template template parameter itself is in scope:
// class template, with a type template parameter with a default
template<typename T = float> struct B {};
// template template parameter T has a parameter list, which
// consists of one type template parameter with a default
template<template<typename = float> typename T> struct A
{
void f();
void g();
};
// out-of-body member function template definitions
template<template<typename TT> class T>
void A<T>::f()
{
T<> t; // error: TT has no default in scope
}
template<template<typename TT = char> class T>
void A<T>::g()
{
T<> t; // ok: t is T<char>
}
this is the link

No diagnostic for pack expansion in std::index_sequence

So I stumbled on this piece of code and I don't understand why the following
construct is not ill-formed.
template<typename T, std::size_t... lst>
struct mystruct : std::index_sequence<lst..., sizeof...(lst)> {
T i;
};
int main() {
mystruct<int> obj;
}
This should be ill-formed since the instantiation of mystruct with T = int will yield the following class(after T is substituted with int):
template<int, std::size_t... lst>
struct mystruct : std::index_sequence<, //Empty list expansion
0> {
int i;
};
How is the std::index_sequence<, 0> not ill-formed? This above compiles without an error.
An empty parameter pack is never "empty" in a way that would make a construct syntactically invalid.
[temp.variadic]
7 When N is zero, the instantiation of the expansion produces an
empty list. Such an instantiation does not alter the syntactic
interpretation of the enclosing construct, even in cases where
omitting the list entirely would otherwise be ill-formed or would
result in an ambiguity in the grammar. [ Example:
template<class... T> struct X : T... { };
template<class... T> void f(T... values) {
X<T...> x(values...);
}
template void f<>(); // OK: X<> has no base classes
// x is a variable of type X<> that is value-initialized
 — end example ]
So it's not std::index_sequence<, 0>, but rather std::index_sequence<0>.
It is not illformed since it expands to std::index_sequence<0>. The parameter pack expansion works not just on a textual level but it also works with the intent of what is done. Otherwise, working with potentially empty parameter packs would be a real mess.

Auto deducing a type template argument from a dependent non-type template argument

I defined a class template X like this:
template <typename T>
using Func = void(T);
template <typename T, Func<T> F>
class X { ... };
Now I can use class X like this:
void func(int i);
X<int, &func> x;
It seems redundant to me to repeat the type int in the declaration of x. Is there a way this can be auto deduced? I mean I want to have a type template Y which can be used via Y<&func> and equals X<int, &func> with auto deduced int.
I tried a lot, even defining crazy templated functions and using decltype, but it seems there is no way to drop the T before naming of &func.
Update: It seems to be a restriction that I am using MSVC 2017.5 which prevents me from using auto in template parameter lists as suggested by Kerrek. I wonder if there is some "hack" to get the same effect without this feature.
Sure, use auto and specialize partially:
template <auto F> struct X;
template <typename T, void (*F)(T)> struct X<F>
{
// ...
};
Usage:
void f(int);
X<f> x; // deduces T = int, F = f in the partial specialization

Compiler errors on partial template speciailzation (c++)

I am trying to do a simple partial template specialization, but I get errors on g++4.4.7, g++4.8.5, clang++3.8.0. Whenever I mention compiler(s) error, I mean the output of all of these, as they always agree.
I am using C++03, compiling without any option.
The code:
#include <iostream>
template <typename T, typename X, typename G>
struct A {};
template <typename T, typename X>
struct A<T, X, void> { A() : n(1) {} X n; T b; };
template <typename X>
struct A<X, void, void> { A() : n(2) {} X n; };
int main() {
A<int, float> one;
A<int> two;
std::cout << one.n << " | " << two.n << "\n";
return 0;
}
Question 1: This code fails to compile. The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. Why?
If I change the original declaration to
template <typename T, typename X = void, typename G = void>
struct A {};
The code compiles and the output is: 1 | 2.
What happens is that the compiler in a first step matches one and two type to the not specialized A, but then it correctly decides to use the code of the partially specialized class one would expect it to use. But it should not need the defaults.
I then decide to change the last partial specialization switching the first and second parameter:
template <typename X>
struct A<void, X, void> { A() : n(2) {} X n; };
I would expect this to change nothing, but the compilers disagree. The clearest output between the 3 is here reported:
a.cpp:7:40: error: field has incomplete type 'void'
struct A<T, X, void> { A() : n(1) {} X n; T b; };
^
a.cpp:14:10: note: in instantiation of template class 'A<int, void, void>' requested here
A<int> two;
^
1 error generated.
Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument?
Note that is the "2nd matching", because if I only use 1 default template argument, the compiler will go back to complaining about the fact that 3 template parameters are needed.
Thanks.
Question 1: This code fails to compile. The compilers say that A<int, float> and A<int> are wrong as A requires 3 templates parameters. Why?
Because A requires 3 template parameters. You declared A as:
template <typename T, typename X, typename G>
struct A {};
There is no two- or one-template parameter version of A. There are versions specialized on some of the types being void, but that's still a parameter - not an absence of parameter.
When you add the defaults, then A<int, float> evaluates as A<int, float, void>, which is a valid instantiation - and picks the specialization which sets n to 1.
You're misunderstanding how specialization works. Specialization doesn't change the number of template parameters. It's just a way of adding special functionality depending on what the template parameters end up being.
Question 2: Why are the compilers considering the two variable an instance of the partial specialization of A that specializes only one argument?
We have three choices
template <T, X, G> struct A; // the primary
template <T, X, void> struct A; // (1)
template <void, X, void> struct A; // (2)
When we instantiate A<int>, that is the same as A<int, void, void> when we add in the default parameters. That does not match (2) - because that one requires the first parameter to be void and yours is int. (1) is a better match than the primary since it's more specialized. But then, (1) has a member of type X and in this case X is deduced as void (from the default parameter), and that's not allowed.

"Name The Template Parameter" Odd Definition

template <bool, class t, class u>// why is bool here,class booltype=bool. Are they equivalent?
struct if_
{
typedef typename t type;
};
template<class t, class u>
struct if_<false, t, u> // what does the <false,t,u> mean?
{
typedef typename u type;
};
The code if from an article named "name the template parameter ". I can't understand the definition of the both struct.
EDIT: Moved the most important part first:
if_<true, int, double>::type; // this is int
if_<false, int, double>::type; // this is double
This conveniently defines a type that can conditionally be defined at compile-time.
Old Answer:
template <bool, class t, class u>// why is bool here,class booltype=bool. Are they equivalent?
struct if_
{
typedef typename t type;
};
This means the first parameter passed to the template is a bool.
It's not equivalent to class booltype=bool. That would be a default typename for the template.
template<class t, class u>
struct if_<false, t, u> // what does the <false,t,u> mean?
{
typedef typename u type;
};
This is a specialization of your struct. If the first parameter passed to the template is false, this it what the struct is defined as.
Basically, assume:
if_<true, int, double> x;
//is defined as
//struct if_
//{
// typedef int type;
//};
and
if_<false, int, double> x;
//is defined as
//struct if_
//{
// typedef double type;
//};
The notation basically tells what to typedef - if the first parameter is true, typedef the second parameter, otherwise the third.
The first is a general template definition of type if_. The bool is a template parameter (template parameters can be types or integral values)
The second is a partial specialization of the same template. PArtial specialization means that you set some of the template parameters, but not all.
Which one gets used is decided like this: if there is an excplicit specialization for the actual template parameters, that specialization is used, otherwise the non-specialized (the forst definition in this case). The non-specialized version acts a "default" selection
struct if_<false, t, u> is a partial sspecialization of the primary template if_ which is instantiated by the compiler whenever the first parameter of the template has the value false, regardless of the other two "type-parameters". You're dealing with "non-type" template parameters here. The primary purpose of this construction is to select either the type t or type u, depending on the value of the first parameter, so that
if_<true, int, double>::type
will be of type int
and
if_<false, int, double>::type
will be of type double. Admittedly quite difficult to grasp if it's your "first contact" with c++ meta-programming, but basically you get an equivalent of the traditional if statement evaluated by the compiler at compile-time.