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.
Related
I just asked this question: Can I get the Owning Object of a Member Function Template Parameter? and Yakk - Adam Nevraumont's answer had the code:
template<class T>
struct get_memfun_class;
template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
using type=T;
};
These is clearly an initial declaration and then a specialization of struct get_memfun_class. But I find myself uncertain: Can specializations have a different number of template parameters?
For example, is something like this legal?
template<typename T>
void foo(const T&);
template<typename K, typename V>
void foo<pair<K, V>>(const pair<K, V>&);
Are there no requirements that specializations must take the same number of parameters?
You seem to confuse the template parameters of the explicit specialization and the template arguments you use to specialize the template.
template<class T> // one argument
struct get_memfun_class; // get_memfun_class takes one template (type) argument
template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
// ^^^^^^^^^^^^^^^^
// one type argument
using type=T;
}; // explicit specialization takes one template argument
Yes, there are three template parameters for the explicit specialization, but that doesn't mean that the explicit specialization takes three arguments. They are there to be deduced. You can form a single type using multiple type parameters, which is what is happening there. Also consider that you can fully specialize a template:
template <>
struct get_memfun_class<void>;
// ^^^^
// one type argument
Here it's the same thing. Yes, the explicit specialization takes no parameters, but that just means that there is none to be deduced and indeed you are explicitly writing a template parameter (void) and so the amount of template arguments of the specialization match those of the primary template.
Your example is invalid because you cannot partially specialize functions.
Are there no requirements that specializations must take the same number of parameters?
There is; and is satisfied in your example.
When you write
template<class T>
struct get_memfun_class;
you say that get_mumfun_class is a template struct with a single template typename argument; and when you write
template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
using type=T;
};
you define a specialization that receive a single template typename argument in the form R(T::*)(Args...).
From the single type R(T::*)(Args...), you can deduce more that one template paramenters (R, T and the variadic Args..., in this example) but the type R(T::*)(Args...) (a method of a class that receive a variadic list of arguments) remain one.
For example, is something like this legal?
template<typename T>
void foo(const T&);
template<typename K, typename V>
void foo<pair<K, V>>(const pair<K, V>&);
No, but (as written in comments) the second one isn't a class/struct partial specialization (where std::pair<K, V> remain a single type), that is legal; it's a template function partial specialization that is forbidden.
But you can full specialize a template function; so it's legal (by example)
template<>
void foo<std::pair<long, std::string>(const std::pair<long, std::string>&);
as is legal the full specialization for get_memfun_class (to make another example)
template<>
struct get_memfun_class<std::pair<long, std::string>> {
using type=long long;
};
I have a class template inside of another class template. The inner class has a static data member. I am struggling to provide a definition for it. The below example works in clang 3.8 but not in gcc-7.1
template <typename T>
struct Out {
template <typename U>
struct In {
static int var;
};
};
template <typename T>
template <typename U>
int Out<T>::template In<U>::var;
gcc gives the error:
error: template definition of non-template ‘int Out<T>::In<U>::var’
int Out<T>::template In<U>::var;
^~~
What do I gotta do to make gcc happy?
Edit: turns out getting rid of template make this work:
template <typename T>
template <typename U>
int Out<T>::In<U>::var;
Which still leaves the question, is template allowed here?
This type of definition would more commonly be seen without the template before In. The template keyword is not needed here because Out<T>::In is a "member of the current specialization".
For the rule specifying when the template keyword is required before a member name, see [temp.names]/4. For the definition of the technical term "member of the current specialization", see [temp.dep.type]/4.
But the keyword is in fact allowed there, since the grammar permits it between any :: and name, and the semantics require only that the name that follows is either used with template arguments or names a class template ([temp.names]/5), and there are no other rules in the Standard to forbid it. And as a note in [temp.names]/5 explains:
[ Note: As is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the -> or . is not dependent on a template parameter, or the use does not appear in the scope of a template. - end note]
template <typename T> class foo2 {
};
Sample 1
template <typename T, template <typename> class foo2>
foo2<T> func2(){
}
Sample 2
template <template <typename T> class foo2>
foo2<T> func2(){
}
I have a template class and I would like to write a function that accepts only that class (with any of it's templates of course)
why does sample 1 works and 2 does not?
Edit:
Please provide an explanation of how the matching happens? Clearly the function in sample 1 takes two template parameters without any default values, however in the call in the main only one parameter is provided.
Edit2:
I want another func2 overload for the templated foo2 class, I already have defined in my code.
template <typename T>
T func2(){
}
Template template parameters define a template name in the body of the function. You have to provide the parameter to instantiate them. This means that the T in
template <template <typename T> class foo2> void func2(foo2<T>);
is not visible elsewhere; only the template name foo2 is.
Your first sample,
template <typename T, template <typename> class foo2> void func2(foo2<T>);
works because the T is a top-level template type parameter, which is
visible to the function body, and
deduced from the function argument.
However, this use case is more easily written with a simple template type parameter and direct use of the class foo2:
template <typename T> void func2(foo2<T>);
See, for example, template parameters and template arguments on cppreference for details
Note, the question was edited after I wrote the above, and the type is no longer used as a function argument. The point about type deduction no longer applies, but the rest of the answer stands.
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
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.