在编译时查找数组中的重复项 [英] Finding duplicates in array at compile time

查看:23
本文介绍了在编译时查找数组中的重复项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习一些更现代的 C++ 实践,例如模板,我决定创建一个天真且简单的命令行参数解析器,它主要在编译时工作,但我已经遇到了 constexpr,基本上我想要做的就是在编译时检查重复条目(在运行时做这件事很简单).

I am trying to learn some more modern C++ practices such as templates, and I decided to create a naive and simple command line argument parser that mostly works at compile time and I am already running into issues with constexpr, essentially all I want to do is check for duplicate entries at compile time (doing it at run time is trivial).

首先,我有一个包含单一配置的结构:

First, I have a structure that holds a single configuration:

struct Arg_Opt_Tuple {
  std::string_view mc{}; // multichar ie "help" 
  char sc{}; // singlechar ie 'h' 
  bool is_flag{}; 
};

现在假设我想创建一个函数(或者最终是一个对象的构造函数),它返回一个固定大小的 std::array,但也在编译时检查重复或空值,我的目标是有它以类似这样的方式调用:

Now let's say I wanted to create a function (or eventually a constructor to an object) that returns a fixed size std::array, but also does some checking at compile time for duplicates or empty values, my goal is to have it called in some fashion similar to this:

constexpr auto ARG_COUNT = 4U;
constexpr auto opts = checked_arr<ARG_COUNT>(
  Arg_Opt_Tuple{"hello", 'h', false},
  Arg_Opt_Tuple{"world", 'g', true},
  Arg_Opt_Tuple{"goodbye", 'h', false}, // <- static_assert('h' == 'h')
  Arg_Opt_Tuple{"hello", 'r', false} // <- static_assert(sv.compare("hello") == 0)
);

我的第一次尝试是使用 std::initializer_list 但遇到了一些问题,在进行了一些谷歌搜索后得出的结论是,将其与 constexpr 结合使用并不是正确的做法.我目前的尝试涉及一个可变参数模板:

My first attempt was to use a std::initializer_list but ran into some issues and after doing some googling came to the conclusion it's not the correct thing to do here in conjunction with constexpr. My current attempt involves a variadic template:

template <std::size_t N, typename... T>
constexpr std::array<Arg_Opt_Tuple, N> checked_arr(T... list) {
  static_assert(N == sizeof...(T));
  return {list...};
}

这行得通,但对于初始化数组来说完全是多余的,我真的希望它可以做一些编译时检查.对于运行时的重复值或错误值很容易,您可以循环并比较或执行 std::find 或其他操作,但是这些似乎在编译时都不起作用,即(我知道这很丑,但您明白了):

This works but is completely superfluous to just initalizing an array, I really want this to be doing some compile time checking. For duplicates or erroneous values at run time is easy, you can just loop through and compare or do std::find or what not, however none of this seems to work at compile time, ie (I know it's ugly but you get the point):

for (std::size_t src_i = 0; src_i < ARG_COUNT; ++src_i) {
  for (std::size_t check_i = 0; check_i < ARG_COUNT; ++check_i) {
    // skip checking self
    if (check_i == src_i) {
      continue;
    }
    // doesnt work obviously
    static_assert(opts[src_i].sc != opts[check_i].sc);
  }
}

那么实现这一目标有多难?这是糟糕的设计吗?任何指针都会很可爱.

So how difficult would this be to achieve? Is this bad design? Any pointers would be lovely.

推荐答案

对于运行时的重复值或错误值很容易,您可以循环并比较或执行 std::find 或其他操作,但是这些在编译时似乎都不起作用

For duplicates or erroneous values at run time is easy, you can just loop through and compare or do std::find or what not, however none of this seems to work at compile time

普通循环确实有效:

template <typename T> constexpr bool has_duplicates(const T *array, std::size_t size)
{
    for (std::size_t i = 1; i < size; i++)
        for (std::size_t j = 0; j < i; j++)
            if (array[i] == array[j])
                return 1;
    return 0;
}

constexpr int foo[] = {1, 2, 3, 4};
static_assert(!has_duplicates(foo, 4));

如果你想在函数中使用 static_assert inside,你需要将数组作为模板参数传递:

If you want to have static_assert inside of a function, you need to pass the array as a template parameter instead:

template <auto &array> constexpr void assert_has_no_duplicates()
{
    constexpr std::size_t size = std::extent_v<std::remove_reference_t<decltype(array)>>;
    static_assert(!has_duplicates(array, size));
}

constexpr int foo[] = {1, 2, 3, 4};

int main()
{
    assert_has_no_duplicates<foo>();
}

或者,如果您更喜欢 std::arrays:

Or, if you prefer std::arrays:

template <auto &array> constexpr void assert_has_no_duplicates()
{
    static_assert(!has_duplicates(array.data(), array.size()));
}

constexpr std::array<int,4> foo = {1, 2, 3, 4};

int main()
{
    assert_has_no_duplicates<foo>();
}

这篇关于在编译时查找数组中的重复项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆