【问题标题】:Check for arguments type in a variadic template declaration [duplicate]检查可变参数模板声明中的参数类型
【发布时间】:2020-02-03 12:19:49
【问题描述】:

我得到了一个普通的可变参数模板声明,就像经典的一样:

template <typename... Arguments>
class VariadicTemplate;

我需要实现的是让VariadicTemplate 类执行一些类型检查;可变参数模板应该以某种迭代形式检查所有收到的参数都应该是&lt;Foo&gt;类型。

我在某处看到过类似的东西,但现在我无法识别它在哪里:P

【问题讨论】:

  • 参见例如this reference 用于类型特征。可以和static_assert一起使用。
  • 好吧,std 引用告诉我要使用哪种静态断言,但它没有提供任何关于如何让这种类型检查在可变参数列表上执行的参考......有某种 for构造要写在 { 但我不记得形式了。

标签: c++ templates variadic


【解决方案1】:
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;
}

但有件事告诉我你想知道参数是否都是类模板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;
}

【讨论】:

  • 注:如果你真的需要,你可以在 O(1) 实例化深度 IIRC 中进行检查——但它会变得更丑陋。
【解决方案2】:

这里有另一个解决方案:P

这里是:

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.");
};

所以你得到了它的工作:

class Foo {};

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

class MyCollection : public CollectionOfCommonBase<Foo, AFoo, BFoo> {};

【讨论】:

    【解决方案3】:

    如果要检查类型(不查询基类型):

    #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;
    

    处理您的示例问题:

    template <typename ... Foos>
    void Foo (Foos ... foos)
    {
        static_assert(are_same_v<int, Foos...>);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-10
      • 2011-12-13
      • 2019-01-30
      • 1970-01-01
      • 2013-10-13
      • 1970-01-01
      相关资源
      最近更新 更多