2010-05-09 2 views
1

Итак, я писал программу на C++, которая позволила бы мне взять под контроль весь мир. Я все сделали писать окончательные единицы перевода, но я получил сообщение об ошибке:Почему bind1st и bind2nd требуют постоянных объектов функции?

error C3848: expression having type 'const `anonymous-namespace'::ElementAccumulator<T,BinaryFunction>' would lose some const-volatile qualifiers in order to call 'void `anonymous-namespace'::ElementAccumulator<T,BinaryFunction>::operator()(const point::Point &,const int &)' 
     with 
     [ 
      T=SideCounter, 
      BinaryFunction=std::plus<int> 
     ] 
     c:\program files (x86)\microsoft visual studio 9.0\vc\include\functional(324) : while compiling class template member function 'void std::binder2nd<_Fn2>::operator()(point::Point &) const' 
     with 
     [ 
      _Fn2=`anonymous-namespace'::ElementAccumulator<SideCounter,std::plus<int>> 
     ] 
     c:\users\****\documents\visual studio 2008\projects\TAKE_OVER_THE_WORLD\grid_divider.cpp(361) : see reference to class template instantiation 'std::binder2nd<_Fn2>' being compiled 
     with 
     [ 
      _Fn2=`anonymous-namespace'::ElementAccumulator<SideCounter,std::plus<int>> 
     ] 

Я посмотрел в спецификации binder2nd и там это было: он принял const AdaptibleBinaryFunction.

Так что, неважно, подумал я. Я просто использовал boost::bind, не так ли?

Неверно! Теперь моя программа take-over-the-world занимает слишком много времени для компиляции (bind используется внутри шаблона, который создается очень много)! В этом случае мой заклятый враг первым захватит мир! Я не могу этого допустить - он использует Java!

Так может кто-то сказать мне, почему это дизайнерское решение было принято? Это похоже на странное решение. Я предполагаю, что я должен сделать некоторые из элементов моего класса mutable сейчас ...

EDIT: Нарушитель код:

template <typename T, typename BinaryFunction> 
class ElementAccumulator 
    : public binary_function<typename T::key_type, typename T::mapped_type, void> 
{ 
public: 
    typedef T MapType; 
    typedef typename T::key_type KeyType; 
    typedef typename T::mapped_type MappedType; 
    typedef BinaryFunction Func; 

    ElementAccumulator(MapType& Map, Func f) : map_(Map), f_(f) {} 

    void operator()(const KeyType& k, const MappedType& v) 
    { 
     MappedType& val = map_[k]; 
     val = f_(val, v); 
    } 
private: 
    MapType& map_; 
    Func f_; 
}; 

void myFunc(int n) 
{ 
    typedef boost::unordered_map<Point, int, Point::PointHash> Counter; 
    Counter side_count; 
    ElementAccumulator<SideCounter, plus<int> > acc(side_count, plus<int>()); 

     vector<Point> pts = getPts(); 
    for_each(pts.begin(), pts.end(), bind2nd(acc, n)); 
} 
+0

Не работает ли это, если вы просто создали свой 'operator() const'? AFAIK, это не повлияет на какие-либо ссылочные элементы (не делает объект refferred постоянным), поэтому вы все равно можете изменить карту. – UncleBens

ответ

0

Ну, попытка какой-то вывод:

Причиной, побуждающей что-либо принимает const-что-либо, - это позволить кому-либо передать в него что-либо const.

Наиболее очевидный const, который вы хотите передать в «функциональные» функции, является ссылкой на временный.

В частности, если bind1st и другие материалы в <functional> взяли неконстантный ссылочный параметр, то вы не смогли бы связать их вместе, чтобы программировать в функциональном стиле. Функциональный стиль не согласуется с идеей захвата временной переменной в одном утверждении, а затем «позже», изменяя эту переменную в «следующем» утверждении. Все очень императивные и побочные.

К сожалению, это означает, что в качестве <functional> определено, что функторы должны быть const в этом случае и предположительно кучкой других случаев. Твой нет.

Поддерживает ли boost :: bind либо const, либо как часть шаблона, где уместно? Если это так, то, возможно, <functional> не делает этого просто потому, что boost :: bind был разработан, когда люди больше понимали, как получить лучшее из шаблонов. Или, может быть, bind1st был разработан с более чистым функциональным мышлением, следовательно, никаких побочных эффектов, поэтому почему бы не все быть const? Возможно, я пропустил часть вопроса - я вижу из примера вашего кода, почему вы хотите использовать привязку параметров, но я не думаю, что очевидно, что заголовок с именем <functional> - это подходящее место для поиска чего-нибудь, что связано с аккумуляторами; -)

5

binder2nd т е р принимает постоянное ссылку к AdaptableBinaryFunction - неconstAdaptableBinaryFunction сами по себе. Как ваш экземпляр-код? Обычно обычно не упоминается binder2nd, а работает через удобную функцию bind2nd (которая просто работает по второму аргументу x с typename Operation::second_argument_type(x) или тому подобным).

0

bind (и старые, устаревшие bind1st и bind2nd) являются ценностно-смысловыми. Обратный объект является автономным и не ссылается на параметры, const или нет.

Для получения ссылочной семантики, перейдите std::ref в bind.

auto defer_by_value = std::bind(fun, foo, bar); // Copy fun, foo, and bar. 

auto defer_by_ref = std::bind(std::ref(fun), std::ref(foo), std::ref(bar)); 
                // Observe fun, foo, and bar. 
+0

К сожалению, это шестилетний вопрос, который попал на первую страницу спам-ботом. Ну что ж… – Potatoswatter

Смежные вопросы