2014-10-11 2 views
4

Пусть у нас есть такой код:вектор обобщенных лямбдах

std::vector<std::function<void()>> tasks; 

И мы добавим задачу так:

tasks.push_back([]() 
{ 
    // ... 
} 

Это работает. Но теперь мы хотим добавить эту задачу:

std::unique_ptr<int> v(new int(10)); 
tasks.push_back([v = std::move(v)]() 
{ 
    // ... 
} 

И этот код не скомпилирован.

Для большей ясности:

std::unique_ptr<int> v(new int(10)); 
std::function<void()> test = [v = std::move(v)]() 
{ 
}; 

Есть ошибки компиляции. Потому что тип лямбда не std::function<void()>. Но каков тип?

+2

Лямбда имеет «нецензурный» уникальную тип, сгенерированный компилятором. Ваша проблема заключается в том, что 'std :: function' требует, чтобы объект функции был' CopyConstructible', а 'unique_ptr' не может быть скопирован. –

+0

Но в примере 'lambda' является ссылкой rvalue, он вызывает конструктор перемещения. Не так ли? – herolover

+1

Это не имеет значения. 'std :: function' имеет жесткое требование, что объект функции, используемый' CopyConstructible', и ваш лямбда не потому, что он захватил 'unique_ptr'. Конец истории. –

ответ

2

Нет лямбда std::function. std::function - это стиратель типа - он требует чего-то уничтожаемого, с возможностью копирования и invokable с подписью и стирает остальную часть типа.

Поскольку ваша лямбда не может быть скопирована, ее нельзя хранить в std::function.

Вы можете сделать это с возможностью копирования (например, сохраняя свое состояние в std::shared_ptr) или написать только для перемещения std::function.

#include <utility> 
#include <memory> 

template<class Sig>class func; 
namespace details{ 
    template<class Sig>struct inner; 
    template<class R,class...Args> 
    struct inner<R(Args...)>{ 
    virtual ~inner() {}; 
    virtual R invoke(Args&&...args) =0; 
    }; 
    template<class F,class Sig>struct impl; 
    template<class F,class R,class...Args> 
    struct impl<F,R(Args...)>:inner<R(Args...)>{ 
    F f; 
    template<class... Ts> 
    impl(Ts&&...ts):f(std::forward<Ts>(ts)...){} 
    R invoke(Args&&...args)override{ 
     return f(std::forward<Args>(args)...); 
    } 
    }; 
} 
template<class T>struct emplace_as{}; 
template<class R,class...Args> 
class func<R(Args...)>{ 
    std::unique_ptr<details::inner<R(Args...)>> pImpl; 
public: 
    R operator()(Args...args){ 
    return pImpl->invoke(std::forward<Args>(args)...); 
    } 
    explicit operator bool()const{return pImpl;} 
    func(func&&)=default; 
    template<class F,class...Ts,class=typename std::enable_if< 
    std::is_convertible<decltype(std::declval<F>()(std::declval<Args>()...)),R>::value 
    >::type> 
    func(emplace_as<F>,Ts&&...ts): 
    pImpl(new details::impl<F, R(Args...)>{std::forward<Ts>(ts)...}) 
    {} 

    template<class F,class=typename std::enable_if< 
    std::is_convertible<decltype(std::declval<F>()(std::declval<Args>()...)),R>::value 
    >::type> 
    func(F&&f): 
    func(
     emplace_as<typename std::decay<F>::type>(), 
     std::forward<F>(f) 
    ) 
    {} 
}; 

или something like that.

(Характеристики, необходимые для быть добавлено: Rvalue ссылки на эти перегрузки на (), может быть swap, может быть assign и emplace, возможно, определением типов для result_type и т.д.), может быть target и target_type)

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