在boost::lambda中使用boost::format

5

由于某些原因,我无法在boost::lambda中使用boost::format。以下是我的代码的一个(希望)可编译的简化版本:

#include <algorithm>
#include <iomanip>
#include <iostream>

#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/lambda/lambda.hpp>

namespace bl = boost::lambda;

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3);
    std::for_each(v.begin(), v.end(), bl::var(std::cout) << std::setw(10) << bl::_1);
    std::for_each(v.begin(), v.end(), bl::var(std::cout) << boost::format("%10d") % bl::_1);
}
  • 第一个std::for_each产生了预期的输出结果
  • 第二个std::for_each只输出空格而没有任何数字

为什么会这样呢?我对boost::lambda不太熟悉,可能会错过一些显而易见的东西。

请不要提供基于std::copy的答案:我的实际代码不适用于std::vector,而是适用于boost::fusion::vector(实际上std::for_eachboost::fusion::for_each)。

2个回答

4
由于某些原因,您的代码会立即评估boost::format("%10d") % bl::_1,而不是在每次调用lambda时评估。
为了防止这种情况发生,您需要使用bl::varboost::format("%10d")包装起来,就像您对std::cout所做的那样。
不幸的是,这样做需要Boost.Lambda推断operator%的返回类型,但它无法推断。因此,必须明确指定返回类型,使用bl::ret。请注意,此返回类型必须是引用,以便std::cout 直接访问返回的对象,而不是它的副本。
因此,我们得到以下代码,可以产生预期输出:
std::for_each(v.begin(), v.end(), bl::var(std::cout) <<
    bl::ret<const boost::format &>(bl::var(boost::format("%10d")) % bl::_1));

是的,这个可以工作,但我不知道为什么它是必要的!boost::lambda::var只有在没有参数是lambda表达式时才是必要的。我旨在使用boost::lambda实现简洁明了的语法:( 很遗憾。 - icecrime

2
我的猜测是,您遇到了一个不再可用的格式。
boost::format f("...");

std::string s = f % ... ;
std::string s2 = f % other options...; // FAIL!  f has been changed by the above use!

换句话说,在格式化中使用%实际上会用您输入的%替换字符串数据。更酷的是,上面的第二个用法将悄悄地失败。
我知道,有点违反直觉,但事实就是这样。

谢谢您的回答,但我相信您提供的代码已经按预期工作。引用boost.format文档:“一旦所有参数都被输入,您可以将格式对象转储到流中。[...]结果字符串在格式对象中保持可访问状态,直到传递另一个参数时,此时它将被重新初始化。”第二个“%”确实重新初始化了格式,但在我的情况下应该是件好事! - icecrime
根据我的经验,它不会有影响,但如果你的情况不同,我建议忽略我的回答。我不知道你的问题可能是什么。 - Edward Strange

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接