Non-Type Variadic Function Templates in C++11

Non-type variadic function templates in C++11

You are simply confusing type names and non-type names. What you want simply doesn’t work.

You can probably use variadic non-type templates in functions, but not as (non-template) arguments:

template <int N, int... Rest>
int max()
{
int tmp = max<Rest...>();
return N < tmp ? tmp : N;
}
std::cout << max<3, 1, 4, 2, 5, 0>() << std::endl;

… although I haven’t tested this and I’m not sure how this should work given that you need to have a partial specialisation as the base case. You could solve this by dispatching to a partially specialised struct:

template <int N, int... Rest>
struct max_t {
static int const value = max_t<Rest...>::value > N ? max_t<Rest...>::value : N;
};

template <int N>
struct max_t<N> {
static int const value = N;
};

template <int... NS>
int max()
{
return max_t<NS...>::value;
}

This will work.

How to resolve this issue with variadic non-type template parameter in C++11?

Here's a solution using std::integer_sequence. It's a C++14 feature, but ports to C++11 do exist (haven't used this, can't vouch for its quality).

template<Enum... es>
class B
{
template <int... Is>
static std::shared_ptr<A> getAHelper(std::integer_sequence<Is...>) {
return std::make_shared<A>(translate(es, Is)...);
}
public:
static std::shared_ptr<A> getA()
{
return getAHelper(std::make_integer_sequence<sizeof...(es)>{});
}
};

C++ variadic template with non-type parameters of different types

You can do it in the following way:

template <class... Types>
struct Wrapper
{
template <Types... args>
class Test {
// ...
};
};

Note that simple notation template <class... Types, Types... args> class Test; is not permitted by standard (see paragraph [temp.param] 14.1/15).

Example of using (note that float, double and long double constants can not be non-type template parameters):

Wrapper<int, char, unsigned>::Test<1, '2', 3U> t;

More specific case with pointers to members can be implemented similarly:

struct Base
{
int a;
float b;
void c() {}
};

template <class... Types>
struct Wrapper
{
template <Types Base::*... args>
class Test {
//
};
};

Example of using:

Wrapper<int, float, void ()>::Test<&Base::a, &Base::b, &Base::c> t2;

This notation can be shortened using variadic macro and decltype keyword.

Template template parameter with mixed type and non-type variadic parameters

It is possible with some modifications:

//type container template
template<typename...>
struct types{};
//declaration
template<typename ,auto V, typename, template<typename ,decltype(V), typename...>class>
class enum_to_type;
//generic definition
template<typename First, typename ... Befors, First V, typename ... Afters, template<typename ,First, typename...>class U>
class enum_to_type<types<First, Befors...>, V, types<Afters...>, U>{
public:
static auto go(){
return U<types<Befors...>, V + 1, Afters...>{};
}
};
//specialization
template<auto V, typename ... Afters, template<typename ,decltype(V), typename...>class U>
class enum_to_type<types<>, V,types<Afters...>, U>{
public:
static auto go(){
return U<types<>, V + 1, Afters...>{};
//or
//return U<types<>, V, Afters...>{};
}
};
//Declarations and specializations for the target class templates
template<typename, int>
struct A{};

template<typename, int, typename>
struct B;
template<typename T, int V>
struct B<types<>, V, T > {};

using next_A = decltype(enum_to_type<types<int>, 0, types<>, A>::go());

template<typename T>
using next_B = decltype(enum_to_type<types<int>, 0, types<T>, B>());

template<typename, auto, typename...>
struct general_case;
template<typename ... befors, int V, typename ... afters>
struct general_case<types<befors...>, V, afters ...> {};

Usage:

decltype(enum_to_type<types<>,  0, types<>, A>::go()) object_A;
decltype(enum_to_type<types<>, 0, types<int>, B>::go()) object_B;
decltype(enum_to_type<types<int, float>, 3, types<int>, general_case>::go()) object_general;

It is just that compiler does not have a way to find out how many types are in before and after. That is why in general it can take only one arguments pack in template declaration. But it can handle multiple arguments packs in specialization!

Good luck!

Non-type variadic template parameter

What's wrong is [temp.arg.nontype] §2.3. String literals cannot (currently) be used as template arguments. What you could do, for example, is declare named array objects and use those as arguments:

template<const wchar_t* ...properties>
class my_iterator {};

int main()
{
static constexpr const wchar_t a[] = L"hello";
static constexpr const wchar_t b[] = L"world";

my_iterator<a, b> inst;
}

working example here

C++ variadic templates with type and non-type argument mixing for recursive inheritance

It's not possible. You'll have to settle for one of the following:

Foo<Bar<int, 5>, Bar<double, 7>> foo_1;
Foo<int, Bar<5>, double, Bar<7>> foo_1;
// ...?

If the values are always integral, you could also try this:

Foo<int[5], double[7]> foo_1;

And then extract elemenet types & extents from each argument.

c++ non-type parameter pack expansion

I see two options here. You can pass a std::initializer_list, which causes the function signature to change to

#include <initializer_list>

template <typename T>
static bool value_in(T&& val, std::initializer_list<T> vals)
{
/* Implementation as before */
}

and the calling snippet to

return value_in(Enumeration::two,
{ Enumeration::one, Enumeration::two }) ? 0 : 1;

Note the additional braces here, they are required to construct the initializer list to be passed. A little detail of this approach is the function signature, which immediately reveals that there is only one type to deduce.

If it feels wrong to type the braces, stick with your original attempt and tweak your function such that

template <typename S, typename... T>
static bool value_in(S&& val, T&&... vals) {
const std::unordered_set<S> allowed {std::forward<T>(vals)...};

/* As before... */
}

This allows for calling the function as in your original snippet. In contrast to the above solution, this signature obviously has two template parameters, which might require a second look to see that it will fail if S differs from T.



Related Topics



Leave a reply



Submit