2015-05-27 3 views
0

У меня есть следующий код:Использование Повысьте эффективность адаптеров с станд :: затруднительное выражения

#include <boost/range/adaptor/transformed.hpp> 
#include <boost/range/algorithm.hpp> 

#include <iostream> 
#include <functional> 
#include <memory> 

struct A { 
    A() = default; 
    A(const A&) = delete; 
    A& operator=(const A&) = delete; 
}; 

struct B { 
    B() = default; 
    B(const B&) = delete; 
    B& operator=(const B&) = delete; 

    int foo(const A&, int b) { 
     return -b; 
    } 
}; 

int main() { 
    A a; 
    auto b = std::make_shared<B>(); 
    std::vector<int> values{1, 2, 3, 2}; 

    using std::placeholders::_1; 
    auto fun = std::bind(&B::foo, b.get(), std::ref(a), _1); 
    int min = *boost::min_element(values | boost::adaptors::transformed(fun)); 
    std::cout << min << std::endl; 
} 

Когда я пытаюсь скомпилировать его, лязг дает следующее сообщение об ошибке (полный выход here):

/usr/local/include/boost/optional/optional.hpp:674:80: error: object of type 'std::_Bind<std::_Mem_fn<int (Base::*)(const A &, int)> (Base *, std::reference_wrapper<A>, std::_Placeholder<1>)>' cannot be assigned because its copy assignment operator is implicitly deleted 

Кажется, что, хотя объект bind имеет конструктор копирования, его оператор назначения копирования удаляется. Я получаю ту же ошибку, если попытаюсь использовать лямбда вместо bind.

  1. Является ли это ошибкой в ​​стандарте C++ 11, реализации libstdC++ или реализации адаптера Boost?

  2. Что является лучшим обходным решением для этого? Я могу обернуть его в std::function. Кажется, что работает и boost::bind. Что является более эффективным, или это действительно имеет значение?

+0

2) 'boost :: bind' более эффективен, чем' std :: function' – David

ответ

3

Вот проблема:

  1. Стандарт не требует std::bind «s возвращаемого значения будет копировать назначаемым; только двигаться конструктивно (и копировать конструктивно, если все связанные объекты также являются копируемыми конструктивными). Для lambdas их операторы присваивания копий должны быть удалены.

  2. Адаптер диапазона фактически использует transform_iterator, поэтому объект функции сохраняется в итераторе.

  3. Итераторы должны быть назначены для копирования, min_element пытается это сделать, и ваша программа взрывается.

С распространением лямбды в C++ 11, я бы назвал это проблемой с библиотекой наддува, который не был разработан с объектами копирований конструктивны, но-не-копией назначаемых функций в виду ,

Я бы на самом деле предлагают обертывание полученный объект функции в reference_wrapper:

int min = *boost::min_element(values | boost::adaptors::transformed(std::ref(fun))); 

Это также экономит стоимость создания дополнительных копий функтора всякий раз, когда итератор копируется.

В двух перечисленных вами параметрах boost::bind должен быть более эффективным, поскольку он не должен выполнять стирание типа.

+0

Спасибо, ссылка завершает работу функции. На самом деле, я считаю, что лучше обернуть лямбда в этом случае. – petersohn

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