Как я могу использовать препроцессор Boost для расширения строки

Я хочу расширить строку неизвестной длины с помощью библиотеки препроцессора Boost.

Например, я хочу это:

const string foo{"bar"};

Быть расширенным моим макросом к этому:

foo [0], foo [1], foo [2], '\ 0'

Вот мой код, который я в основном скопировал отсюда:

#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/control/deduce_d.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/tuple/elem.hpp>

#define EXPAND(first, last) BOOST_PP_REPEAT( BOOST_PP_INC( BOOST_PP_SUB((last), (first)), EXPAND_M, ((first), BOOST_DEDUCE_D())), '\0'

#define EXPAND_M(z, n, data) EXPAND_M_2((n), BOOST_PP_TUPLE_ELEM(2, 0, (data)), BOOST_PP_TUPLE_ELEM(2, 1, (data)))

#define EXPAND_M_2(n, first, d) foo[BOOST_PP_ADD_D((d), (n), (first))],

Могу ли я просто использовать это так?

const string foo{"bar"};

cout << string{ EXPAND(0, foo.size()) } << endl;

2 ответа

Решение

Поскольку препроцессор работает только с токенами, вам нужно будет указать длину строки, передаваемой в foo как жестко закодированная магическая константа, то есть целочисленный литерал. Там нет никакого способа обойти это.
И поскольку этот целочисленный литерал будет независим от строкового литерала, весь подход подвержен ошибкам и его следует избегать.

Попробуйте вместо этого использовать шаблоны с переменными значениями, если вы ищете гибкие расширения. (Трудно сказать, что вы должны использовать, так как вы не предоставили вариант использования, для которого это нужно!)

Вы просто ищете способ включить (завершающий) NUL-символ?

#include <algorithm>
#include <iterator>
#include <iostream>
#include <sstream>

template <typename R = std::string, size_t N>
R stringlit(char const(&lit)[N]) {
    return R(lit+0, lit+N);
}

static std::string const foo(stringlit("bar"));
static auto        const bar(stringlit<std::vector<int>>("bar"));

int main() { 
    std::cout << "foo: ";
    for(char ch : bar)
        std::cout << std::showbase << std::hex << static_cast<int>(ch) << " ";

    std::cout << "\nbar: ";
    for(int i : bar)
        std::cout << std::showbase << std::hex << i << " ";
}

Печать

foo: 0x62 0x61 0x72 0 
bar: 0x62 0x61 0x72 0 

Возможно связанный вариант:

Вы также можете использовать псевдонимы шаблона, чтобы иметь возможность явно указывать размер литерала массива с помощью временного:

template <typename T> using Alias = T;

static std::string const foo(stringlit(Alias<char[7]>{"bar"})); // 4 trailing '\0's
Другие вопросы по тегам