Trying to define a template function that takes a template argument - c++

I'm trying to define a template function that takes a container, which is also a template type. I need to know what the template type of the container is (E) (so I can refer to it in the code, e.g. E element = *iterator;). Here's my attempt:
template <template <typename E> T>
void sort(T& container){ ... }
I think this means "sort is a template function that takes a template argument T. T is a template type that takes a template argument E".
However I get the error:
expected 'class' before T.
When I put 'class' there, it says:
variable or field 'sort' declared void
What am I doing wrong with the syntax?

There are other ways to achieve the same function. What you need is a template template parameter. A working example is:
template <typename E, template <typename> class T>
void sort(T<E>& container){}
main(){}
In the template signature, T is declared to be a (dependent) type that takes another type parameter. That parameter itself (E) needs to be declared and supplied to T, just as you would use in vector<int>.
You could also use:
template <typename E, template <typename, typename...> class T>
if your container type expects optional parameters such as traits.

Related

Issue with template template parameter in function template

I am trying to use a template template parameter and my code will not complile.
template<class DataType, template<class T> class Container>
void foo(Container<DataType> test)
{
}
int main()
{
std::vector<int> testVec{1,2,3,4};
foo<int, std::vector>(testVec);
}
The error message is
"No matching function for call to 'foo'.
Candidate template ignored: invalid explicitly-specified argument for template parameter 'Container'"
Can someone help me out?
Suggestion: try with
// ...............................VVVVVVVVV
template<class DataType, template<class ...> class Container>
void foo(Container<DataType> test)
{
}
The problem is that std::vector accept two type template parameters; the second one with a default value.
If you write
// ...............................VVVVVVV
template<class DataType, template<class T> class Container>
you ask for a template-template parameter that accept a single type template parameter.
So you can solve asking two type template parameters
// ...............................VVVVVVVVVVVV
template<class DataType, template<class, class> class Container>
or, to be more flexible, a variadic list of type template parameters
// ...............................VVVVVVVVV
template<class DataType, template<class ...> class Container>
As pointed by HolyBlackCat (thanks) your code (so a template-template parameter asking for a single type template parameter) should fail before C++17 but should be accepted starting from C++17 (the matching rules are changed).
Unfortunately this works with g++ but not for clang++: the clang++ developer doesn't implement, by default, this new C++17 matching rule.
But HolyBlackCat report that also clang++ accept your code adding a special parameter: -frelaxed-template-template-args.

Function with multiple template specifiers

I do not understand the template defined below, can somebody help me decode it?
template <typename Impl>
template <typename datadec, typename T>
inline datadec<Impl>::codec(const T& value)
{
return codec<datadec>(Master::char_data(value), Master::size(value));
}
First of all, in case this isn't clear, the snippet as given by the OP doesn't compile. In keeping with what I believe is the intention behind it, two minimal modifications are needed to make it compile:
template <typename Impl>
template <typename datadec, typename T>
inline auto ::datadec<Impl>::codec(const T& value)
{
codec<datadec>(Master::char_data(value), Master::size(value));
}
To answer the question, let's go over this line by line:
So, the datadec class template takes the single template argument typename Impl. Hence the first line:
template <typename Impl>
Now, the next two lines:
template <typename datadec, typename T>
inline auto ::datadec<Impl>::codec(const T& value)
constitute a definition for a member function template codec() of this class template datadec (so it's a member function template of a class template). This function template itself takes two template arguments: typename datadec and typename T. Note that the first template argument here is of the same name as the class template itself -- datadec.
Notice: In the OP there was a return value type missing from this function declaration.
Next we see what's inside the member function definition:
{
return codec<datadec>(Master::char_data(value), Master::size(value));
}
there's a call to a different codec() that is explicitly being used with a template argument that gets the datadec template parameter passed from the outside and takes two non-template arguments: Master::char_data(value) and Master::size(value).
Edit: In an attempt to shed light on the "dual role" of the datadec name in this snippet -- as it seems to raise some eyebrows that this argument (taken by the member function template) is of the same name as the class template itself, as noted above: Without being provided more context by the OP, let's imagine, from a design perspective, that the class template datadec represents some data decoder and that codec() returns some codec related data. Then one reasonable explanation for these templated declarations to be as they are is that codec() needs to know what type of data decoder it needs to use for its return value -- as in, you could specialize the two argument version of codec() for different types of datadec.

What does this syntax mean, `class template <class R, class ...Args> class name<R(Args...)>`

I've been trying more about multi threaded programming in c++, and i was having difficulty understanding std::promise so i began searching for answers on this website, and low and behold, there is somebody with the same question as me. But reading the answer made me even more confused
this is the code in the answer that presumably is a similar implementation of std::packaged_task
template <typename> class my_task;
template <typename R, typename ...Args>
class my_task<R(Args...)>
{
std::function<R(Args...)> fn;
std::promise<R> pr; // the promise of the result
public:
template <typename ...Ts>
explicit my_task(Ts &&... ts) : fn(std::forward<Ts>(ts)...) { }
template <typename ...Ts>
void operator()(Ts &&... ts)
{
pr.set_value(fn(std::forward<Ts>(ts)...)); // fulfill the promise
}
std::future<R> get_future() { return pr.get_future(); }
// disable copy, default move
};
in this code,
1- what does this syntax mean template <typename R, typename ...Args> class my_task<R(Args...)>, more specifically, what is the purpose of <R(Args...)> ?
2- why is there a foroward decleration for the class?
thanks
There was some brief discussion in the comments how 1 and 2 should be two separate questions, but I believe that they both are just two sides to the same exact question, for the following reasons:
template <typename> class my_task;
template <typename R, typename ...Args>
class my_task<R(Args...)>; ....
The first statement declares a template that takes a typename as its sole template parameter. The second statement declares a specialization for that template class.
In this context:
R(Args...)
Will specialize for any typename that matches a function. This template specialization will match any template instantiation that passes a function signature for a typename. Barring any problems within the template itself, this template specialization will be used for:
my_task<int (const char *)>
or, a function that takes a const char * parameter and returns an int. The template specialization will also match:
my_task<Tptr *(Tptr **, int)>
or, a function that takes two parameters, Tptr ** and an int, and returns a Tptr * (here, Tptr is some other class).
The template specialization will NOT match:
my_task<int>
Or
my_task<char *>
Because they are not function signatures. If you try to instantiate this template using a non-function typename you're going to get a compilation error. Why?
Well, that's because the template is not defined:
template<typename> class my_task;
Don't think of this as just a forward declaration. it's a forward declaration of a template that takes a template parameter, and the template will not be defined anywhere. Rather, the template declaration allows for a subsequent template specialization declaration, that will match only specific types passed as a template parameter.
This is a common programming technique for restricting the kinds of typenames or classes that can be used with a particular template. Instead of allowing a template to be used with just any typename or class, the template can only be used with some subset. In this case, a function typename, or signature.
It also makes it easier for the template itself to explicitly reference -- in this case -- to the template parameter's return type, and the parameter types. If the template has just a bland, single typename as a template parameter, it can't easily access the function's return type, or the function parameter's types.
1: What does this syntax mean template <typename R, typename ...Args> class my_task<R(Args...)>
This is a specialization of the class template my_task. The <R(Args...)> after the name means it is specialized for that type, and that type is a function. R(Args...) is the type of a function taking Args parameters and returning R. So, my_task<void()> mt; for example would make Args be an empty parameter pack, and R would be void.
2: Why is there a forward declaration for the class?
The class is declared, but unlike an ordinary forward declaration, the un-specialized version isn't defined. This class is only intended to work when the type is a function, so if someone tries to use something that isn't a function (like my_task<int>), it will give an error about the type being undefined.
my_task<void*(int, int)> mt1; //R = void*, Args = int, int
my_task<int> mt2; //error: use of undefined class

How to read the template partial specialization?

Suppose the following declaration:
template <typename T> struct MyTemplate;
The following definition of the partial specialization seems to use the same letter T to refer to different types.
template <typename T> struct MyTemplate<T*> {};
For example, let's take a concrete instantiation:
MyTemplate<int *> c;
Now, consider again the above definition of the partial specialization:
template <typename T> struct MyTemplate<T*> {};
In the first part of this line (i.e. template <typename T>), T is int *. In the second part of the line (i.e. MyTemplate<T*>), T is int!
So, how is the definition of the partial specialization read?
Read it like this:
The primary template says "MyTemplate is a class template with one type parameter":
template <typename> struct MyTemplate;
The partial specialization says, "whenever there exists a type T"...
template <typename T>
... such that a specialization of MyTemplate is requested for the type T *"...
struct MyTemplate<T *>
... then use this alternative definition of the template.
You could also define explicit specializations. For example, could say "whenever the specialization is requested for type X, use this alternative definition:
template <> struct MyTemplate<X> { /* ... */ };
Note that explicit specializations of class templates define types, wheras partial specializations define templates.
To see it another way: A partial class template specialization deduces, or pattern-matches, the structure of the class template arguments:
template <typename T> struct MyTemplate<T *>
// ^^^^^^^^^^^^ ^^^^^
// This is a new template Argument passed to the original class
// template parameter
The parameter names of this new template are matched structurally against the argument of the original class template's parameters.
Examples:
MyTemplate<void>: The type parameter of the class template is void, and the primary template is used for this specialization.
MyTemplate<int *>: The type parameter is int *. There exists a type T, namely T = int, such that the requested type parameter is T *, and so the definition of the partial specialization of the template is used for this specialization.
MyTemplate<X>: The parameter type is X, and an explicit specialization has been defined for that parameter type, which is therefore used.
The correct reading of the specialisation is as follows:
template <typename T> // a *type pattern* with a *free variable* `T` follows
struct MyTemplate<T*> // `T*` is the pattern
When the template is instantiated by MyTemplate<int*>, the argument is matched against the pattern, not the type variable list. Values of the type variables are then deduced from the match.
To see this more directly, consider a template with two arguments.
template <typename T1, typename T2>
struct A;
and its specialisation
template <typename T1, typename T2>
struct A<T1*, T2*>;
Now you can write the latter as
template <typename T2, typename T1>
struct A<T1*, T2*>;
(the variable list order is reversed) and this is equivalent to the previous one. Indeed, order in the list is irrelevant. When you invoke A<int*, double*> it is deduced that T1=int, T2=double, regardless of the order of T1 and T2 in the template head.
Further, you can do this
template <typename T>
struct A<T*, T*>;
and use it in A<int*, int*>. It is now plainly clear that the type variable list has no direct correspondence with the actual template parameter list.
Note: the terms "pattern", "type variable", "type pattern matching" are not standard C++ terms. They are pretty much standard almost everywhere else though.
You have this line:
MyTemplate<int *> c;
Your confusion seems to come from assuming that the int * in < > somehow corresponds to the T in template <typename T>. It does not. In a partial specialisation (actually in every template declaration), the template parameter names are simply "free variable" (or perhaps "placeholder") names. The template arguments (int * in your case) don't directly correspond to these, they correspond to what is (or would be) in the < > following the template name.
This means that the <int *> part of the instantiation maps to the <T*> part of the partial specialisation. T is just a name introduced by the template <typename T> prefix. In the entire process, the T is int.
There is no contradiction. T should be read as T, T* is T*.
template <typename T> struct MyTemplate<T*> {};
"In the first part of this line (i.e. template <typename T>), T is int *."
No - in template <typename T> T is int, in struct MyTemplate<T*> {}; T is also int.
"Note that when a partial specialization is used, a template parameter is deduced from the specialization pattern; the template parameter is not simply the actual template argument. In particular, for Vector<Shape*>, T is Shape and not Shape*." (Stroustrup C++, 4th ed, 25.3, p. 732.)

How can I deduce the type and its template arguments for a meta-function?

Suppose I have a meta-function which requires both the type and its arguments. How can I do this without forcing the user of the function to provide both the type and its arguments separately?
using MyType = SomeType<T1, T2, T3>; // This is the type to pass to the functor
template <typename MyType, typename ... Args>
struct MetaFunction
{
using type = SomeOperation<MyType, Args...>;
}
// I want to be able to call my functor like this:
MetaFunction<MyType>::type;
// but with the above I have to call it like this:
MetaFunction<MyType, T1, T2, T3>::type;
How can I do this?
You can "disassemble" a class template specialization into the template itself and the template parameters by using partial spezialiation (some form of pattern-matching).
First, we define MetaFunction to be a (class) template that takes a type as its only parameter:
template <typename T>
struct MetaFunction;
Then, we define a partial specialization of this class template MetaFunction. A partial specialization is a special case of a class template. If the case applies, the partial specialization is used instead of the original (primary) template to make a class. The template "interface", i.e. the amount and kind of template arguments you can/must provide to instantiate the MetaFunction template is not changed by the existence of specializations.
A partial specialization, as opposed to an explicit specialization, is also a template, which implies that it has template parameters. The partial means that it does not specify fully for which types (sets of template arguments) it applies as a special case. Typically, partial specializations apply to subsets of the set of possible/valid arguments you can supply to the primary template.
template <template<typename...> class TT, typename ... Args>
struct MetaFunction /* not finished yet */
There are three kinds of template parameters:
Type parameters
"Value" parameters (non-type)
Template parameters
This partial specialization uses a template template-parameter. A valid argument for such a parameter must be a either a class template or an alias template.
We specify when this partial specialization shall be used by providing a "pattern":
template <template<typename...> class TT, typename ... Args>
struct MetaFunction<TT<Args...>>
{
using type = SomeOperation<TT, Args...>;
};
This partial specialization will be used if the type supplied to the MetaFunction template matches the pattern TT<Args...>, i.e., if it can be disassembled into a class/alias(*) template TT and some template type parameters Args.
(*) As T.C. correctly noted, a type produced via an alias-template is not associated with the alias-template. Therefore, you cannot deduce an alias-template from a type.