代码之家  ›  专栏  ›  技术社区  ›  Joald

使用折叠表达式检查可变模板参数是否唯一

  •  11
  • Joald  · 技术社区  · 7 年前

    给定一个可变模板参数包,我想使用 inline constexpr bool fold expressions . 我试着这样做:

    template<class... T>
    inline static constexpr bool is_unique = (... && (!is_one_of<T, ...>));
    

    哪里 is_one_of 是一个工作正常的类似布尔。 但无论我在is\u one\u中输入了什么,这一行都不会编译。这甚至可以使用折叠表达式来实现,还是需要使用正则结构来实现?

    2 回复  |  直到 5 年前
        1
  •  12
  •   Vittorio Romeo    7 年前

    你的方法没有真正起作用,因为 is_one_of 需要使用类型调用 T 剩下的所有类型 不包括 T . 没有办法用一个 折叠表达式 在单个参数包上。我建议改用专业化:

    template <typename...>
    inline constexpr auto is_unique = std::true_type{};
    
    template <typename T, typename... Rest>
    inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
        (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
    >{};   
    

    用法:

    static_assert(is_unique<>);
    static_assert(is_unique<int>);
    static_assert(is_unique<int, float, double>);
    static_assert(!is_unique<int, float, double, int>);
    

    live example on wandbox.org


    (感谢 Barry 对于使用 折叠表达式 .)

        2
  •  2
  •   max66    7 年前

    --编辑--

    我在谷歌上找到了一个 interesting solution 这给了我避免递归和避免大量警告的灵感

    因此可以定义类型为的包装器

    template <typename>
    struct wrapT
     { };
    

    以及从类型的包装器继承的类型和整数的包装器

    template <typename T, std::size_t>
    struct wrapTI : public wrapT<T>
     { };
    

    接下来,您可以定义 foo 递归地 继承自 wrapTI

    template <typename T,
              typename = std::make_index_sequence<std::tuple_size<T>::value>>
    struct foo;
    
    template <typename ... Ts, std::size_t ... Is>
    struct foo<std::tuple<Ts...>, std::index_sequence<Is...>>
       : public wrapTI<Ts, Is>...
     { };
    

    现在 is_unique 可能是

    template <typename ... Ts>
    static constexpr bool isUnique
       = ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
    

    重点是 foo<Ts...> 可以转换为 wrapT<T> 只有 foo<Ts&燃气轮机; 从继承一次(且仅继承一次) 包裹(<);T> ,即如果 T 在中出现一次(并且只有一次) Ts... .

    下面是一个完整的编译示例

    #include <tuple>
    #include <type_traits>
    
    template <typename>
    struct wrapT
     { };
    
    template <typename T, std::size_t>
    struct wrapTI : public wrapT<T>
     { };
    
    template <typename T,
              typename = std::make_index_sequence<std::tuple_size<T>::value>>
    struct foo;
    
    template <typename ... Ts, std::size_t ... Is>
    struct foo<std::tuple<Ts...>, std::index_sequence<Is...>>
       : public wrapTI<Ts, Is>...
     { };
    
    template <typename ... Ts>
    static constexpr bool isUnique
       = ( ... && std::is_convertible<foo<std::tuple<Ts...>>, wrapT<Ts>>::value );
    
    int main ()
     {
       static_assert( true == isUnique<int, long, long long> );
       static_assert( false == isUnique<int, long, long long, int> );
     }