Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the type of parameters in a parameter pack

So let's say we have the following code:

#include <stack>

template<class... Args>
auto make_stack(Args&&... args)
{
    std::stack<INSERT_TYPE_HERE> s;
    return s;
}

int main()
{
    auto s = make_stack(1, 2.2, 3); //would be std::stack<double>
    auto s2 = make_stack(1l, 2, 3); //would be std::stack<long>
}

How would I find the common type of the arguments in the parameter pack?

like image 980
DeiDei Avatar asked Dec 05 '15 19:12

DeiDei


People also ask

What is parameter pack c++?

A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments.

What is Variadic template in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

How do you expand a parameter pack?

Parameter packs can only be expanded in a strictly-defined list of contexts, and operator , is not one of them. In other words, it's not possible to use pack expansion to generate an expression consisting of a series of subexpressions delimited by operator , .


2 Answers

Use std::common_type from <type_traits>. It is a type trait that provides the common type all types can be converted to. So in your case you'd need:

template<typename... Args>
auto make_stack(Args&&... args)
{
    using commonT = std::common_type_t<Args...>;
    std::stack<commonT> s;
    return s;
}

EDIT As @DietmarKühl mentioned in the comment, you may want to use a std::decay on commonT if you use C++11 and not C++14. It looks like the std::decay is applied on the resulting type only since C++14.

like image 122
vsoftco Avatar answered Oct 06 '22 01:10

vsoftco


Unfortunately, there are no guarantees that the types are the same.
You can use std::common_type, but be aware that (from the documentation):

Determines the common type among all types T..., that is the type all T... can be implicitly converted to.

This means that it could be not the one that you expect it to be.

Anyway, by looking at your example, it looks to me that your problem can be easily solved by means of a templated function like the one below and the use of an initializer_list.
It follows a working example:

#include <initializer_list>
#include <stack>

template<typename T>
auto make_stack(std::initializer_list<T> list)
{
    std::stack<T> s;
    return s;
}

int main()
{
    auto s = make_stack<double>({1, 2.2, 3}); //would be std::stack<double>
    auto s2 = make_stack<long int>({1l, 2, 3}); //would be std::stack<long>
}
like image 32
skypjack Avatar answered Oct 06 '22 00:10

skypjack