4

I got a plain variadic template declaration, just like the classic one:

template <typename... Arguments>
class VariadicTemplate;

What I need to achieve is in by letting the VariadicTemplate class do perform some type checking; the variadic template should check in some iterative form that all the arguments received should be let say of the type <Foo>.

I have seen something similar somewhere but now I can not recognize where it was :P

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
user3004291
  • 71
  • 1
  • 4
  • 4
    See e.g. [this reference](http://en.cppreference.com/w/cpp/types) for type traits. Can be used together with [`static_assert`](http://en.cppreference.com/w/cpp/language/static_assert). – Some programmer dude Nov 18 '13 at 10:38
  • Well the std reference tells me which kind of static assertion to use but it does not supply any reference to how let such type checking being performed on a variadic argument list...there is some kind of for construct to be written before { but I don remember the form. – user3004291 Nov 18 '13 at 11:08

3 Answers3

7
struct Foo {};

#include <type_traits>

template<class T, class...>
struct are_same : std::true_type
{};

template<class T, class U, class... TT>
struct are_same<T, U, TT...>
    : std::integral_constant<bool, std::is_same<T,U>{} && are_same<T, TT...>{}>
{};

template<typename... Arguments>
class VariadicTemplate
{
    static_assert(are_same<Foo, Arguments...>{}, "a meaningful error message");
};

int main()
{
    VariadicTemplate<Foo, Foo, Foo, Foo> v0{}; (void)v0;
    VariadicTemplate<Foo, int, Foo, double> v1{}; (void)v1;
}

But something tells me you want to know if the arguments are all specializations of a class template Foo:

template<class T, class U>
struct Foo {};

#include <type_traits>

template<template<class...> class T, class U>
struct is_template_of
{
    template<class... TT>
    static std::true_type test(T<TT...>*);

    static std::false_type test(...);

    constexpr static bool value = decltype(test((U*)nullptr)){};
};

template<template<class...> class T, class...>
struct is_template_of_N : std::true_type
{};

template<template<class...> class T, class U, class... TT>
struct is_template_of_N<T, U, TT...>
    : std::integral_constant<bool,    is_template_of<T,U>::value
                                   && is_template_of_N<T, TT...>{}>
{};

template<typename... Arguments>
class VariadicTemplate
{
    static_assert(is_template_of_N<Foo, Arguments...>{},
                  "a meaningful error message");
};

int main()
{
    VariadicTemplate<Foo<int, double>, Foo<int, int>> v0; (void)v0;
    VariadicTemplate<Foo<int, double>, int> v1; (void)v1;
}
dyp
  • 38,334
  • 13
  • 112
  • 177
  • N.B. If you really need to, you can do this check in O(1) instantiation depth IIRC -- but it'll get much uglier. – dyp Nov 18 '13 at 12:21
3

Here there is anothe solution :P

Here it is:

template <bool... b> struct static_all_of;

// do recursion if the first argument is true
template <bool... tail>
struct static_all_of<true, tail...> : static_all_of<tail...> {};

// end recursion if first argument is false
template <bool... tail>
struct static_all_of<false, tail...> : std::false_type {};

// end recursion if no more arguments need to be processed
template <> struct static_all_of<> : std::true_type {};


// First template argument is given as the type checking for the is_base_of() function

template <typename Type, typename... Requirements>
class CollectionOfCommonBase : public Requirements...
{
  static_assert(static_all_of<std::is_base_of<Type, Requirements>::value...>::value, "One or more template arguments are not base_of the one specified - given template specialization is not allowed.");
};

So you got it working for:

class Foo {};

class AFoo : public Foo {};
class BFoo : public Foo {};

class MyCollection : public CollectionOfCommonBase<Foo, AFoo, BFoo> {};
Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50
user3004291
  • 71
  • 1
  • 4
0

If you want to check the types (not inquiring about base types):

#include <type_traits>

template <typename ...>
struct are_same : std::true_type {};

template <typename S, typename T, typename ... Ts>
struct are_same <S, T, Ts...> : std::false_type {};

template <typename T, typename ... Ts>
struct are_same <T, T, Ts...> : are_same<T, Ts...> {};

template <typename ... Ts>
inline constexpr bool are_same_v = are_same<Ts...>::value;

Handling your example problem:

template <typename ... Foos>
void Foo (Foos ... foos)
{
    static_assert(are_same_v<int, Foos...>);
}
Elliott
  • 2,603
  • 2
  • 18
  • 35