【问题标题】:How can I make this variadic template code shorter using features from C++14 and C++1z?如何使用 C++14 和 C++1z 的功能使这个可变参数模板代码更短?
【发布时间】:2016-03-05 15:59:36
【问题描述】:

这是一个代码 sn-p,我将使用它来检查可变参数模板类型是否唯一:

template <typename...>
struct is_one_of;

template <typename F>
struct is_one_of<F> {
    static constexpr bool value = false;
};

template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
    static constexpr bool value =
        std::is_same<F, S>::value || is_one_of<F, T...>::value;
};

template <typename...>
struct is_unique;

template <>
struct is_unique<> {
    static constexpr bool value = true;
};

template <typename F, typename... T>
struct is_unique<F, T...> {
    static constexpr bool value =
        is_unique<T...>::value && !is_one_of<F, T...>::value;
};

int main() {
    constexpr bool b = is_unique<bool, int, double>::value;
    constexpr bool c = is_unique<int, char, int>::value;
    static_assert(b == true && c == false, "!");
}

有没有什么方法可以使用 C++14 和 C++1z 中引入的功能使这段代码更短和/或更简洁?或者有没有更好的方法来使用新功能达到同样的效果?

对于 C++1z,我的意思是:最新版本的 Clang 和 GCC 中已经提供的功能。

【问题讨论】:

  • 不,这很简洁。但是,当引入折叠表达式时,您将能够执行以下操作:constexpr static bool value = std::is_same&lt;F, T&gt;::value || ...
  • @BrianRodriguez:我认为这需要圆括号。
  • 你可以用一点小技巧让is_one_of更简洁一点:coliru.stacked-crooked.com/a/3b9755f28193a13b
  • @PiotrSkotnicki 是的,完全正确。它是否使用了除折叠表达式之外的任何新功能(C++11 中不存在或未开发到该阶段)?

标签: c++ c++14 variadic-templates template-meta-programming c++17


【解决方案1】:

我们最近在 C++1z 草案中添加了std::disjunction,它可用于is_one_of(一旦找到匹配项就会停止实例化,更多详细信息请参见链接):

template <typename F, typename... T>
  using is_one_of = std::disjunction<is_same<F, T>...>;

这已经在 GCC 主干中实现。对于旧版本的 GCC,您可以改用实现细节 __or_

template <typename F, typename... T>
  using is_one_of = std::__or_<is_same<F, T>...>;

或者使用 C++11 工具手动实现disjunction,如上面链接的提案末尾所示。

【讨论】:

    【解决方案2】:
    #include <type_traits>
    
    template <typename F, typename... Ts>
    constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);
    
    template <typename...>
    constexpr bool is_unique = true;
    
    template <typename F, typename... Ts>
    constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;
    

    DEMO

    【讨论】:

      【解决方案3】:

      我(现在)建议使用 std::conj/disj/nega 系列 STL 函数:

      #include <type_traits>
      
      template <typename H, typename... T>
      struct is_one_of : std::disjunction<std::is_same<H, T>...> {};
      
      template <typename H, typename... T>
      struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {};
      
      template <typename H>
      struct is_unique<H> : std::true_type {};
      
      int main()
      {
          static_assert(is_one_of<int, char, double, int, bool>::value);
          static_assert(is_unique<int, char, double, bool>::value);
          static_assert(!is_unique<int, int, char, double, bool>::value);
      }
      

      当为这些情况设计的fold-expressions 发布到语言中时,这将变得微不足道:

      namespace stx = std::experimental;
      
      template <typename H, typename... T>
      struct is_one_of {
          static constexpr bool value = (stx::is_same_v<H, T> || ...);
      };
      
      template <typename H, typename... T>
      struct is_unique {
          static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value);
      };
      
      template <typename H>
      struct is_unique<H> : std::true_type {};
      

      【讨论】:

      • 您的is_unique 仅检查H 是否唯一,但其他Ts 仍可能在类型列表中有重复项。
      • 这段代码以多种不同的方式被破坏,很明显它从未经过最低限度的测试。
      • @T.C.明天起床后我会换。我最近才允许自己使用这些新功能,但在享受这么多乐趣等时忘记了解决这个问题
      • @T.C.完毕。现在阻止它编译的是constexpr-ness 的std::any_of
      【解决方案4】:

      就折叠表达式部分而言,我与 Brian Rodriguez 和 Piotr Scontnincki 的回答一致。在折叠表达式出现之前,您可以通过删除不完整的主模板来稍微缩小现有代码,如下所示:

      template <typename...>
      struct is_one_of {
          static constexpr bool value = false;
      };
      
      template <typename F, typename S, typename... T>
      struct is_one_of<F, S, T...> {
          static constexpr bool value =
              std::is_same<F, S>::value || is_one_of<F, T...>::value;
      };
      
      template <typename...>
      struct is_unique {
          static constexpr bool value = true;
      };
      
      template <typename F, typename... T>
      struct is_unique<F, T...> {
          static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value;
      };
      

      【讨论】:

        猜你喜欢
        • 2021-05-02
        • 1970-01-01
        • 1970-01-01
        • 2015-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多