【问题标题】:helper function to check a value is any of its parameters检查值的辅助函数是它的任何参数
【发布时间】:2020-05-21 23:33:58
【问题描述】:

我需要使用辅助函数检查 T 类型的值是否是它的任何参数。

例如,使用类似下面的代码

enum class my_enum{k1, k2, k3, k4, k5};
auto v{my_enum::k1};
if (is_any_of(v, my_enum::k1, my_enum::k4, my_enum::k5)) {
}

而不是使用if (v == my_enum::k1 || v == my_enum::k4 || v== my_enum::k5) {}switch-case

如何在 C++11 中实现可变参数函数bool is_any_of()

使用 C++17 折叠表达式如何让实现变得更简单?

【问题讨论】:

  • 您是否假设参数的类型可能不同,如果是,是否应该将它们直接与 v== 进行比较,或者将它们转换为 v 的类型第一?
  • 参数的类型可能不同,可以直接与== 进行比较——这是我的假设。谢谢。
  • 不是元编程专家,所以我无法提供C++11 版本,但C++17 版本非常简单:template <typename... Ts> constexpr bool is_any_of(const my_enum value, Ts&& ... ts) { return ((value == ts) || ...); }
  • @Fureeish 是的。这适用于 C++17 折叠表达式,更一般地与 template <typename T, typename ... Ts> constexpr bool is_any_of(T v, Ts&& ... ts) { return ((v == ts) || ...); 一起使用,谢谢,但我正在寻找 C++11 解决方案,因为我目前正在研究 C++11 代码库。

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


【解决方案1】:

这将在 C++11 中工作,并且只要所有类型都可以相互比较,就会做你想做的事。

template<typename T, typename R>
bool is_any_of(T t, R r)
{
   return t == r;
}

template<typename T, typename R, typename... ARGS>
bool is_any_of(T t, R r, ARGS... args)
{
   if (t == r)
   {
      return true;
   }
   else
   {
      return is_any_of(t, args...);
   }
}

这更加紧凑,可以在 C++17 中使用

template<typename T, typename... ARGS>
bool is_any_of(T t, ARGS... args)
{
   return ((t == args) || ...);
}

【讨论】:

  • 您可能应该通过转发引用来获取所有参数并正确转发它们。
【解决方案2】:

对于非递归 C++11 替代方案:

template <typename T, typename... Ts>
bool is_any_of (T t, Ts&&... ts) {
    std::initializer_list<bool> eq { (t == ts)... };
    return std::any_of(eq.begin(), eq.end(), [](bool i){ return i; });
}

https://godbolt.org/z/K7xtia

但正如已经回答的一样,折叠表达式return ((t == ts) || ...); 更紧凑、更具表现力和可优化性。

【讨论】:

    【解决方案3】:

    您已经收到了很好的基于模板的解决方案。我自己写了一个,但它重复了另一个答案。所以,这个答案是不同的,但它也不使用模板。相反,它使用可变参数宏。

    如果您需要真正的短路行为,则需要扩展完整的表达式。否则,如果参数有副作用,将它们传递给函数将触发所有这些。作为一个人为的例子,

    template <typename T>
    const T & x(const T &v) {
        std::cout << __func__ << ": " << v << '\n';
        return v;
    }
    
      //...
      if (is_any_of(2, x(1), x(2), x(3))) {
        //...
      }
    

    当在x(2) 上检测到匹配时,短路实现将避免调用x(3)。但是,这需要将 is_any_if(...) 扩展为:

      if ((2 == x(1)) || (2 == x(2)) || (2 == x(3))) {
        //...
    

    您可以使用宏来完成此扩展。下面是一种可能的实现,它最多需要 9 个参数来进行测试。

    #define is_any_of(...) \
            (V_(V_(is_any_of_X(__VA_ARGS__,A,9,8,7,6,5,4,3,2,_))(__VA_ARGS__)))
    
    #define is_any_of_X(_A,_9,_8,_7,_6,_5,_4,_3,_2,_1,X,...) is_any_of_##X
    
    #define is_any_of_A(V, X, ...) ((X) == (V)) || is_any_of_9(V, __VA_ARGS__)
    #define is_any_of_9(V, X, ...) ((X) == (V)) || is_any_of_8(V, __VA_ARGS__)
    #define is_any_of_8(V, X, ...) ((X) == (V)) || is_any_of_7(V, __VA_ARGS__)
    #define is_any_of_7(V, X, ...) ((X) == (V)) || is_any_of_6(V, __VA_ARGS__)
    #define is_any_of_6(V, X, ...) ((X) == (V)) || is_any_of_5(V, __VA_ARGS__)
    #define is_any_of_5(V, X, ...) ((X) == (V)) || is_any_of_4(V, __VA_ARGS__)
    #define is_any_of_4(V, X, ...) ((X) == (V)) || is_any_of_3(V, __VA_ARGS__)
    #define is_any_of_3(V, X, ...) ((X) == (V)) || is_any_of_2(V, __VA_ARGS__)
    #define is_any_of_2(V, X)      ((X) == (V))
    #define is_any_of_1(...)       false
    #define is_any_of_0(...)       true
    
    #define is_any_of_Y(_1,Y,...) is_any_of_##Y
    #define is_any_of__(...) I_(is_any_of_Y, E_ __VA_ARGS__ () 0, 1)(__VA_ARGS__)
    
    #define V_(...) __VA_ARGS__
    #define I_(M,...) V_(M(__VA_ARGS__))
    #define E_() _,
    

    该技术在here 进行了解释。简而言之,它应用了一个宏参数计数技巧,以及一种可移植的方法来检测单个参数情况是否实际上是空参数情况。 (如果使用GCC,检测可以简化。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      • 2022-01-12
      • 2016-01-08
      • 1970-01-01
      • 2014-07-29
      • 2013-09-12
      • 1970-01-01
      相关资源
      最近更新 更多