boost :: function & boost :: lambda снова - PullRequest
0 голосов
/ 05 июня 2010

Продолжение публикации: Использование * Спецификаторов ширины и точности С boost :: format

Я пытаюсь использовать boost::function для создания функции, которая использует лямбда-выражения для форматирования строки с boost::format. В конечном итоге я пытаюсь добиться использования спецификаторов ширины и точности для строк с форматом. boost::format не поддерживает использование спецификаторов ширины и точности *, как указано в документах :

Ширина или точность установлены на звездочку (*) используются printf для чтения этого поля из аргумента. например Е ( "% 1 $ d:% 2 $ * 3 $ D:.% 4 $ * 3 $ d \ п.", час, мин, точность, сек); Этот класс не поддерживает этот механизм для сейчас. поэтому такие поля точности или ширины игнорируются при синтаксическом анализе.

поэтому я пытаюсь найти другие способы достижения той же цели.

Вот то, что у меня есть, но оно не работает:

#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, вероятно, отсутствует. Как я могу заставить это работать?

Ответы [ 2 ]

2 голосов
/ 06 июня 2010

Я думаю, что для этого случая вы бы хотели использовать 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;
}
1 голос
/ 06 июня 2010

Вы должны снова проверить документацию Boost.Lambda и посмотреть, на что он способен, а на что нет. Например, поскольку оператор точки не перегружен, вы не можете вызывать функцию-член, например str(), в таком лямбда-выражении. Вам нужно использовать bind для этого:

bind(&format::str, … )

На самом деле это распространяется на все вызовы неоператорных функций, насколько я могу судить. Что касается создания объекта формата, вам нужно отложить его создание примерно так:

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

Вы видите, что со всем дополнительным шумом (связывание, конструктор, константа) вы получаете довольно сложное, длинное и трудноразрешимое лямбда-выражение. Лучше всего, вероятно, вообще избежать этого и просто использовать простой функциональный объект

struct myfunctor {
    string operator()(int a, string b) const {
        return …
    }
};
…
void foo() {
    …
    boost::function<string(int, string)> f = myfunctor();
    …
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...