如何使用Boost预处理器扩展字符串

时间:2022-12-04 00:16:20

I want to expand a string of unknown length with Boost's preprocessor library.

我想用Boost的预处理器库扩展一个未知长度的字符串。

For example I want this:

例如,我想要这个:

const string foo{"bar"};

To be expanded by my macro to this:

要通过我的宏扩展到这个:

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

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

Here is my code, which I have mostly copied from here:

这是我的代码,我大部分从这里复制:

#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))],

Can I just use it like this?

我可以像这样使用它吗?

const string foo{"bar"};

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

2 个解决方案

#1


3  

As the preprocessor only works with tokens you will have to provide the length of the string passed to foo as a hard-coded magic constant, i.e. an integer literal. There's no way around this.
And as this integer literal would be independent from the string literal, the whole approach is error-prone and should be avoided.

由于预处理器仅适用于令牌,因此您必须提供传递给foo的字符串的长度作为硬编码的魔术常量,即整数字面值。没有办法解决这个问题。并且由于此整数文字将独立于字符串文字,因此整个方法容易出错,应该避免。

Try to use variadic templates instead, if flexible expansions are what you are looking for. (It's hard to tell what you should use as you didn't provide the use-case you need this for!)

如果您正在寻找灵活的扩展,请尝试使用可变参数模板。 (很难说你应该使用什么,因为你没有提供你需要的用例!)

#2


3  

Are you simply looking for a way to include the (trailing) NUL character?

您是否只是想找到一种方法来包含(尾随)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 << " ";
}

Prints

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

Perhaps related variation:

也许相关的变化:

You can also employ template aliases to be able to specify the array literal's size explicitly with a temporary:

您还可以使用模板别名,以便能够使用临时明确指定数组文字的大小:

template <typename T> using Alias = T;

static std::string const foo(stringlit(Alias<char[7]>{"bar"})); // 4 trailing '\0's

#1


3  

As the preprocessor only works with tokens you will have to provide the length of the string passed to foo as a hard-coded magic constant, i.e. an integer literal. There's no way around this.
And as this integer literal would be independent from the string literal, the whole approach is error-prone and should be avoided.

由于预处理器仅适用于令牌,因此您必须提供传递给foo的字符串的长度作为硬编码的魔术常量,即整数字面值。没有办法解决这个问题。并且由于此整数文字将独立于字符串文字,因此整个方法容易出错,应该避免。

Try to use variadic templates instead, if flexible expansions are what you are looking for. (It's hard to tell what you should use as you didn't provide the use-case you need this for!)

如果您正在寻找灵活的扩展,请尝试使用可变参数模板。 (很难说你应该使用什么,因为你没有提供你需要的用例!)

#2


3  

Are you simply looking for a way to include the (trailing) NUL character?

您是否只是想找到一种方法来包含(尾随)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 << " ";
}

Prints

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

Perhaps related variation:

也许相关的变化:

You can also employ template aliases to be able to specify the array literal's size explicitly with a temporary:

您还可以使用模板别名,以便能够使用临时明确指定数组文字的大小:

template <typename T> using Alias = T;

static std::string const foo(stringlit(Alias<char[7]>{"bar"})); // 4 trailing '\0's