2014-10-13 2 views
4

Я бы хотел направить вызов функтора и скопировать этот функтор только тогда, когда это абсолютно необходимо. Вот моя общая функция обертка и функтор:Вперед функторы с минимальным копированием

template <typename F> 
void wrapper (F func) 
{ 
    func(); 
} 

struct Functor 
{ 
    Functor() {} 
    void operator()() { /* do some work */ } 
}; 

Я могу назвать обертка с

  1. ссылка Rvalue: обертка (Functor());
  2. lvalue reference: Functor f; Обертка (е);
  3. const lvalue reference: const Functor f; Обертка (е);
  4. const rvalue reference: const Functor make_functor(); wrapper (make_functor());

Я хочу скопировать аргумент обертки только тогда, когда были переданы ссылки на const. Поэтому я пришел к такой реализации обертки:

using safe_mutual_handler_type = 
    typename std::conditional< 
    std::is_reference<F>::value 
    , typename std::conditional< 
     std::is_const<typename std::remove_reference<F>::type>::value 
    , typename std::remove_const<typename std::remove_reference<F>::type>::type 
    , F& 
    >::type 
    , F& 
    >::type; 

template <typename F> 
void wrapper (F&& func) 
{ 
    safe_mutual_handler_type<F> tmp = func; 
    tmp(); 
} 

Не очень хорошие и промаха (не очень типичные) Const-Rvalue ссылок случай, но в основном, делаю свою работу.

Но я также может иметь Functor с сопзЬ оператором()

struct Functor { 
    Functor() {} 
    void operator()() const {} 
}; 

И в этом случае мне не нужно копировать ARG обертки вообще.

Вопрос в том, как я могу проверить упаковку, если Функтор имеет оператор скобки в скобках? Другой вопрос в том, может ли обертка реализовать более умным и компактным способом без огромного количества строк типа typedefs? (на самом деле я беспокоюсь не о размере кода, а о читаемости кода).

ответ

5

Если вы просто хотите использовать ссылки, если вызов с ними справедливо, используйте выражение SFINAE:

template <typename F> 
auto wrapper_ (F&& func, int) -> decltype(func()) 
{ 
    func(); 
} 

template <typename F> 
void wrapper_ (F func, ...) 
{ 
    func(); 
} 

template <typename F> 
void wrapper (F&& f) 
{ 
    wrapper_(std::forward<F>(f), 0); 
} 

Если вы хотите скопировать/переместить его, когда вы передаете изменяемую ссылку (и только тогда) :

template <typename F> 
auto wrapper_ (F&& func, std::true_type) 
{ 
    func(); 
} 

template <typename F> 
void wrapper_ (F func, std::false_type.) 
{ 
    func(); 
} 

template <typename F> 
void wrapper (F&& f) 
{ 
    wrapper_(std::forward<F>(f), std::is_const<typename std::remove_reference<F>::type>()); 
} 

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

  • Нет связанных вопросов^_^