【问题标题】:How Can I Use Boost preprocessor to Expand a String如何使用 Boost 预处理器扩展字符串
【发布时间】:2015-02-20 14:59:19
【问题描述】:

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

例如我想要这个:

const string foo{"bar"};

由我的宏扩展为:

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

这是我的代码,大部分是从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))],

我可以这样用吗?

const string foo{"bar"};

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

【问题讨论】:

  • 长度必须是文字形式。
  • @Columbo Welp,这有点破坏了整个计划。我想这是有道理的。由于这是预处理器,预处理器如何知道何时停止?如果我能以某种方式将值绑定回foo,而不是使用硬编码的3,我的代码会更简洁。你知道有什么方法可以做到这一点,只要 foo 是在编译时定义的?
  • 预处理器仅适用于令牌。标记 3 必须包含在某处,你甚至不能编写一个函数来将字符串文字的长度作为整数文字。
  • @Columbo 你能把这个写成我接受的答案吗?并不是说我对此感到高兴,因为这意味着我浪费了很多时间:(
  • 我对我的回答有点不满意(事实上我得到了支持)。你能提供更多的上下文吗?您是否只是选择将字符串扩展为字符序列?通过使用上限(例如 256)确实可以做到这一点。Boost.PP 的重复是可能的,但也可以使用自己的二进制递归方法。 '

标签: c++ boost recursion macros boost-preprocessor


【解决方案1】:

您是否只是在寻找一种包含(尾随)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

【讨论】:

  • 这是什么巫术? __PRETTY_FUNCTION__?这是一些有趣的代码,但遗憾的是,我实际上是在尝试创建一个initializer_listColumbo 帮助我意识到如果不明确指定变量大小就无法完成:(
  • 那个漂亮的函数名纯粹是为了调试。我的代码具有相同的效果,在您的示例中添加初始化列表。
  • 好吧,在您添加 Alias 代码之前,我明白您在做什么。现在我不确定我是否理解。那里发生了什么?
  • @JonathanMee 这只是奖金(因为确实这个问题并不清楚你为什么想要你描述的东西)。它只是概括了初始化 char-array-reference 的字符串文字的概念,以便您可以覆盖 char-array 的长度。随意忽略它。
  • 所以我这里的代码应该解决这个问题:stackoverflow.com/questions/27504692/… 我认为问题是我想要的是中间步骤,使用initializer_list。你给了我一个更好的方法来完成最后一步,除非我在某个地方有严重的误解。你会同意我试图用initializer_list 做的事情是不可能的,对吧?
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 2013-03-18
    • 2018-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 2019-08-12
    • 2018-01-04
    相关资源
    最近更新 更多