Использование шаблонной функции, которая принимает массив фиксированной длины по ссылке, шаблонизированный по длине массива:
#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.
EDIT
ОП спросил в комментариях о создании класса во время компиляции, членами которого являются строковый литерал и счетчик его токенизации (что-то также упоминалосьнасчет статических учеников, но я не совсем понимаю вариант использования). Это было сложнее! После некоторой работы вышеприведенную функцию 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;
}
Я не уверен, что здесь необходима идеальная пересылка, но я использую ее для пересылки строкового литералааргумент члена класса. Вспомогательная функция wrapArray
предотвращает необходимость двойной вставки всех строковых литералов времени компиляции, т.е. избегает constexpr Foo<sizeof("a,b,c")> wrappedArrayStr("a,b,c",',');
.