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",',');
.
我有一个在编译时用 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",',');
.