【问题标题】:How to make a variadic is_same?如何制作可变参数is_same?
【发布时间】:2013-06-06 14:33:09
【问题描述】:

如何创建一个类模板来返回它的任何可变参数类型是否等于第一个类型。我希望能够做到这一点:

is_same<T, A, B, C>::value; // true if T is one of A, B or C

如果T 等于其中任何一种类型,则其静态value 成员将为true,否则为false。我该怎么做?

【问题讨论】:

  • 由于您的意图不明确(两个人做出了相同的错误解释),我冒昧地稍微改写一下您的问题。

标签: c++ templates c++11 variadic-templates


【解决方案1】:

C++17 简洁明了:

template <class T, class... Ts>
struct is_any : std::disjunction<std::is_same<T, Ts>...> {};

还有对偶:

template <class T, class... Ts>
struct are_same : std::conjunction<std::is_same<T, Ts>...> {};

使用折叠表达式的变体:

template <class T, class... Ts>
struct is_any : std::bool_constant<(std::is_same_v<T, Ts> || ...)> {};

template <class T, class... Ts>
struct are_same : std::bool_constant<(std::is_same_v<T, Ts> && ...)> {};

【讨论】:

  • 这比选中的答案要干净得多,我觉得它应该得到复选标记,即使问题有 c++11 标签
  • 第一个变体适用于 C++14,添加 disjunction 将使其在 C++11 上也能编译。
  • 我喜欢析取/合取解决方案。可以写成 C++20 的概念吗?
【解决方案2】:

使用模板递归:

template<typename T, typename... Rest>
struct is_any : std::false_type {};

template<typename T, typename First>
struct is_any<T, First> : std::is_same<T, First> {};

template<typename T, typename First, typename... Rest>
struct is_any<T, First, Rest...>
    : std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value>
{};

static_assert(is_any<int, char, double, int>::value, "error 1");   // OK
static_assert(is_any<int, char, double, short>::value, "error 2"); // error

【讨论】:

    【解决方案3】:

    在 C++17 中,您有一个更好的解决方案,使用模板变量和折叠表达式:

    template<class T, class... Rest>
    inline constexpr bool are_all_same = (std::is_same_v<T, Rest> && ...);
    

    而且用法也比其他所有例子都简单:

    are_all_same<T, A, B, C>
    

    没有::value,没有括号!

    【讨论】:

    • 这种方法的问题是它不是真正的传递友好。我不能让我自己的类型特征成为东西,然后通过简单地继承它来将它链接到are_all_same。同样的问题也适用于别名模板。所以我还是比较喜欢用mavam发的方法。
    • 没错,但请注意,在 C++20 中,您可以将其转化为概念,然后组合就变得微不足道了。
    【解决方案4】:

    类似的东西。首先,一个小的元编程库,因为它添加了大约 2 行来通用:

    template<template<typename,typename>class checker, typename... Ts>
    struct is_any_to_first : std::false_type {};
    
    template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
    struct is_any_to_first<checker, T0, T1, Ts...> :
      std::integral_constant< bool, checker<T0, T1>::value || is_any_to_first<checker, T0, Ts...>::value>
    {};
    

    然后是is_any_same_to_first 的两行实现:

    template<typename... Ts>
    using is_any_same_to_first = is_any_to_first< std::is_same, Ts... >;
    

    为了完整起见,原来的is_all 也可能有用:

    template<template<typename,typename>class checker, typename... Ts>
    struct is_all : std::true_type {};
    
    template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts>
    struct is_all<checker, T0, T1, Ts...> :
      std::integral_constant< bool, checker<T0, T1>::value && is_all<checker, T0, Ts...>::value>
    {};
    
    template<typename... Ts>
    using is_all_same = is_all< std::is_same, Ts... >;
    

    Live example 中的is_all_same

    请注意,调用is_any_same_to_first 任何不太明确的内容都是自找麻烦。 2/3 试图回答这个问题的人,包括我在内,都认为is_same&lt;A,B,C&gt; 是真的,只要这三个都是同一类型!

    【讨论】:

    • 嗯,我看到你做出了与我不同的决定(is_all_same 而不是is_any)。说实话,我犹豫要不要让 OP 澄清一下。
    • 嗯...此代码仅在 all 类型相同的情况下才有效。我正在寻找 Teither AB 还是 C
    【解决方案5】:

    使用宽松的 C++14 constexpr 函数,这些类型的东西更容易编码,而且编译速度可能也更快,所以你可以这样写:

    template <class T, class ... Candidates>
    constexpr bool is_all_same() {
        bool pairs[] = {std::is_same<T,Candidates>::value...};
        for(bool p: pairs) if(!p) return false;
        return true;
    }
    
    template <class T, class ... Candidates>
    constexpr bool is_any_same() {
        bool pairs[] = {std::is_same<T,Candidates>::value...};
        for(bool p: pairs) if(p) return true;
        return false;
    }
    

    这是因为在 C++14 中 constexpr 函数可以有 for 循环。

    【讨论】:

    • 不是 is_same_vc++17 吗?也许必须使用 is_same::value 和 c++14
    • @xwl 你说得对,is_same&lt;&gt;{} 也适用于 C++14,因为 struct is_same&lt;&gt; 有一个 operator bool 重载。
    【解决方案6】:

    通用的版本:

    • C++11 起

    • 没有依赖(不需要#include &lt;type_traits&gt;

    • 只有一个名称 is_same 适用于 n 类型(不需要 is_same_all

    template <typename First, typename Second, typename ... Next>
    struct is_same {
    
        template <typename A, typename B>
        struct is_same_min {
            enum { value = false };
        };
    
        template <typename A>
        struct is_same_min<A,A> {
            enum { value = true };
        };
    
        template <typename X, typename Y>
        constexpr static bool check() {
            return is_same_min<X,Y>::value;
        };
    
        template <typename X, typename Y, typename Z, typename ... K>
        constexpr static bool check() {
            return is_same_min<X,Y>::value and check<Y, Z, K...>();
        };
    
        enum { value = check<First, Second, Next...>() };
    };
    
    

    只需使用is_same&lt;T1,T2,T3...&gt;::value

    【讨论】:

      猜你喜欢
      • 2010-10-15
      • 1970-01-01
      • 2015-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 2022-01-01
      相关资源
      最近更新 更多