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