C++17 在逗号上拆分 constexpr 字符串并在编译时有元素数?

C++17 split constexpr string on comma and have the number of elements at compile time?

我有一个在编译时用 char 数组表示的逗号分隔的字段列表:

constexpr static char arrayStr[] = "a,b,c";

我想在“,”上拆分,并获得编译时可用的元素数量。伪代码:

constexpr static size_t numFields = SPLIT(arrayStr, ",");

会 return 3.

有什么方法可以使用 C++17 实现吗?

I would like to convert the char array to string, then split on "," and have the number of elements available at compile time.

如果 "string" 你的意思是“std::string”,它不是 constexpr 所以它与编译时计算不兼容。

如果对于 "string" 你接受 C 风格的字符串,char const *,如果你对单个 char 的分隔符感兴趣,你可以尝试如下操作

#include <iostream>

constexpr static char arrayStr[] = "a,b,c";

constexpr std::size_t SPLIT (char const * str, char sep)
 {
   std::size_t  ret { 1u };

   while ( *str )
      if ( sep == *str++ )
         ++ ret;

   return ret;
 }

int main ()
 {
   constexpr auto numFields = SPLIT(arrayStr, ',');

   std::cout << numFields << std::endl;  // print 3
 }

使用通过引用接受固定长度数组的模板化函数,根据数组的长度进行模板化:

#include <iostream>
#include <array>

constexpr char arrayStr[] = "a,b,c";

template<size_t N>
constexpr size_t numFields(const char(&arrayStr)[N], char delim) {
    size_t count = 1;
    for (const auto& ch : arrayStr) {
        if (ch == delim) {
            ++count;
        }
    }
    return count;
}

using namespace std;
int main(int argc, char *argv[]) {
    array<string,numFields(arrayStr,',')> x;
    cout << x.size() << endl;
}

将箭头 arrayStr 模板化为固定大小的数组参数,允许基于范围的 for 循环。

编辑

OP 在评论中询问有关在编译时创建一个 class 的问题,其成员包括字符串文字及其标记化计数(关于静态 class 成员也提到了一些内容,但我用例不清楚)。这更棘手!经过一些工作,上面的 numFields 函数可以与这样的东西一起使用:

class Foo {
public:
    template<typename T>
    constexpr Foo(T&& str, char delim)
    : _array(std::forward<T>(str)),
      _count(numFields(_array,delim)) {
    }

    auto data() const {
        return _array;
    }

    size_t size() const {
        return _count;
    }

private:
    const char (&_array)[N];
    const size_t _count;
};


template<typename T>
constexpr auto wrapArray(T&& str, char delim) -> Foo<sizeof(str)> {
    return Foo<sizeof(str)>(std::forward<T>(str),delim);
}

constexpr auto wrappedArrayStr = wrapArray("a,b,c",',');

using namespace std;
int main(int argc, char *argv[]) {
    cout << wrappedArrayStr.size() << endl;
    cout << wrappedArrayStr.data() << endl;
}

我不确定这里的完美转发是否有必要,但我用它来将字符串文字参数转发给class成员。辅助函数 wrapArray 避免了必须双重粘贴所有编译时字符串文字,即避免 constexpr Foo<sizeof("a,b,c")> wrappedArrayStr("a,b,c",',');.