2015-01-28 3 views
0

Давайте рассмотрим следующий пример:Инициализация класса с лямбда передается в конструктор, C++ 11

#include <functional> 
#include <iostream> 

using namespace std; 

class Caller { 
public: 
    Caller(function<void()> callback) { 
    callback(); 
    } 
}; 

main() { 
#if defined(ONELINER) 
    Caller caller = [] { cout << "test"; }; 
#else 
    function<void()> fun = [] { cout << "test"; }; 
    Caller caller(fun); 
#endif // defined(ONELINER) 
} 

Если мы просто попытаться скомпилировать его (с -std = C++ 11 флагу) будет счастливо закончить , и показ test при запуске. Однако, если мы определим ONELINER макрос компиляции будет завершаться:

prog.cpp: In function 'int main()': 
prog.cpp:17:40: error: conversion from 'main()::<lambda()>' to non-scalar type 'Caller' requested 
    Caller caller = [] { cout << "test"; }; 

Я понимаю, что это вызвано тем, что существует неявное преобразование из лямбда в std::function, а затем неявное преобразование из std::function в Caller, и мы не можем выполнить 2 конверсии одновременно.

Возможно ли сделать синтаксис Class object = lambda;? Я спрашиваю, потому что я играл в последнее время с написанием собственной небольшой рамки тестирования для образовательных целей, и я подумал, что это:

UNIT_TEST(test_name) { 
    // test content 
}; 

гораздо более элегантно, чем

UNIT_TEST_BEGIN(test_name) 
    // unit test 
UNIT_TEST_END() 

Первого может быть достигнута с лямбдой передается в конструктор UnitTest. Но проблема, которую я описал, я должен был использовать грязные обходной путь, как:

#define UNIT_TEST(test_name) \ 
    ::std::function<void(::Helper*)> test_name_helper; \ 
    ::UnitTest test_name ## _test = \ 
     test_name_helper = \ 
     [&] (::Helper* helper) 

и не выглядеть элегантно на всех. Но даже если это можно сделать без lambdas, я все еще заинтригован, может ли быть достигнут синтаксис Class object = lamda;.

+1

Большинство стандартных функций с вызываемым аргументом используют * шаблоны *. –

+0

Не могли бы вы немного разобраться? 'std :: function' является шаблоном, так что, полагаю, у вас есть конкретный случай использования? –

ответ

2

Измените конструктор, как, например:

template<typename CB> 
Caller(CB callback) { 
    callback(); 
} 

Это позволит ему принимать любые вызываемую аргумент, будь то лямбда, std::function, указатель функции или функтор.

К сожалению, конструктор также будет принимать любой тип другого, а также, но дает ошибку компилятора при callback не может быть «под названием» как функция.

+0

Блестящий! Это так просто, что теперь я чувствую себя дураком. –

+1

На стороне примечания: быстрый поиск показал, что проблема принятия-всего также может быть решена с помощью правильных статических утверждений (http://stackoverflow.com/questions/22882170/c-compile-time-predicate-to-test-if -a-вызываемый-объект-оф-типа-F-может-быть-называется). –

+1

TBH, если 'callback' используется в списке инициализаторов для инициализации функции' std :: < > ', вы получите разумную ошибку сразу. Для этого вам не требуется дополнительное статическое утверждение. – MSalters

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

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