代码之家  ›  专栏  ›  技术社区  ›  John Dibling

再次使用boost::函数和boost::lambda

  •  0
  • John Dibling  · 技术社区  · 14 年前

    后续工作: Using * Width & Precision Specifiers With boost::format

    我想用 boost::function 创建使用lambda格式化字符串的函数 boost::format . 最后,我尝试实现的是对格式字符串使用宽度和精度说明符。 Boo::格式 不支持使用 * 宽度和精度说明符,如图所示 in the docs :

    宽度或精度设置为星号(*) 被printf用于读取此字段 从争论中。例如 printf(“%1$d:%2$*3$d:%4$*3$d\n”, 小时、分钟、精度、秒);本课程 不支持此机制 现在。所以这样的精度或宽度字段 被分析悄悄地忽略。

    所以我想找到其他方法来实现同样的目标。

    以下是目前为止我所拥有的,但不起作用的:

    #include <string>
    #include <boost\function.hpp>
    #include <boost\lambda\lambda.hpp>
    #include <iostream>
    #include <boost\format.hpp>
    #include <iomanip>
    #include <boost\bind.hpp>
    
    int main()
    {
     using namespace boost::lambda;
     using namespace std;
    
     boost::function<std::string(int, std::string)> f =
      (boost::format("%s") % boost::io::group(setw(_1*2), setprecision(_2*2), _3)).str();
    
     std::string s = (boost::format("%s") % f(15, "Hello")).str();
    
        return 0;
    }
    

    这会产生许多编译器错误:

    1>------ Build started: Project: hacks, Configuration: Debug x64 ------
    1>Compiling...
    1>main.cpp
    1>.\main.cpp(15) : error C2872: '_1' : ambiguous symbol
    1>        could be 'D:\Program Files (x86)\boost\boost_1_42\boost/lambda/core.hpp(69) : boost::lambda::placeholder1_type &boost::lambda::`anonymous-namespace'::_1'
    1>        or       'D:\Program Files (x86)\boost\boost_1_42\boost/bind/placeholders.hpp(43) : boost::arg<I> `anonymous-namespace'::_1'
    1>        with
    1>        [
    1>            I=1
    1>        ]
    1>.\main.cpp(15) : error C2664: 'std::setw' : cannot convert parameter 1 from 'boost::lambda::placeholder1_type' to 'std::streamsize'
    1>        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
    1>.\main.cpp(15) : error C2872: '_2' : ambiguous symbol
    1>        could be 'D:\Program Files (x86)\boost\boost_1_42\boost/lambda/core.hpp(70) : boost::lambda::placeholder2_type &boost::lambda::`anonymous-namespace'::_2'
    1>        or       'D:\Program Files (x86)\boost\boost_1_42\boost/bind/placeholders.hpp(44) : boost::arg<I> `anonymous-namespace'::_2'
    1>        with
    1>        [
    1>            I=2
    1>        ]
    1>.\main.cpp(15) : error C2664: 'std::setprecision' : cannot convert parameter 1 from 'boost::lambda::placeholder2_type' to 'std::streamsize'
    1>        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
    1>.\main.cpp(15) : error C2872: '_3' : ambiguous symbol
    1>        could be 'D:\Program Files (x86)\boost\boost_1_42\boost/lambda/core.hpp(71) : boost::lambda::placeholder3_type &boost::lambda::`anonymous-namespace'::_3'
    1>        or       'D:\Program Files (x86)\boost\boost_1_42\boost/bind/placeholders.hpp(45) : boost::arg<I> `anonymous-namespace'::_3'
    1>        with
    1>        [
    1>            I=3
    1>        ]
    1>.\main.cpp(15) : error C2660: 'boost::io::group' : function does not take 3 arguments
    1>.\main.cpp(15) : error C2228: left of '.str' must have class/struct/union
    1>Build log was saved at "file://c:\Users\john\Documents\Visual Studio 2005\Projects\hacks\x64\Debug\BuildLog.htm"
    1>hacks - 7 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
    

    我对Boost的lambdas和函数的基本理解可能是缺乏的。我怎样才能让这个工作?

    2 回复  |  直到 13 年前
        1
  •  2
  •   sellibitze    13 年前

    我认为,对于这种情况,您应该使用boost.bind而不是boost.lambda。问题的一部分是boost::io::group是一个函数模板,它接受并返回数量可变的对象,这使得很难为函数声明创建适当的签名。我将用一个简单的签名创建一个字符串格式函数,然后使用boost.bind从中创建一个特定的格式函数。即

    #include <string>
    #include <iomanip>
    #include <boost/function.hpp>
    #include <boost/format.hpp>
    #include <boost/bind.hpp>
    
    using namespace boost;
    using namespace std;
    
    string fmt_str(const string& s, int w, int p)
    {
        return (format("%s") % io::group(setw(w), setprecision(p), s)).str();
    }
    
    int main()
    {
        function<string (int, string)> f = bind(fmt_str, _2, _1, _1);
        string s = f(15, "Hello");
        return 0;
    }
    
        2
  •  1
  •   sellibitze    14 年前

    您应该再次检查boost.lambda的文档,看看它能做什么,不能做什么。例如,由于点运算符不可重载,因此不能像这样调用成员函数 str() 在这样的lambda表达式上。你需要使用 bind 为此:

    bind(&format::str, … )
    

    据我所知,这实际上扩展到了所有非运算符函数调用。对于创建格式对象,您需要通过如下方式推迟它的创建:

    constructor<boost::format>(constant("%s"))  // untested
    

    您可以看到,有了所有额外的噪声(绑定、构造函数、常量),您就得到了一个相当复杂、很长且难以破译的lambda表达式。最好的方法可能是完全避免它,只使用一个简单的函数对象

    struct myfunctor {
        string operator()(int a, string b) const {
            return …
        }
    };
    …
    void foo() {
        …
        boost::function<string(int, string)> f = myfunctor();
        …
    }