mercredi 28 janvier 2015

Initializing class with a lambda passed into constructor, C++11

Lets consider following example:



#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)
}


If we simply try to compile it (with -std=c++11 flag) it will happily finish, and display test when run. However if we define ONELINER macro compilation will fail with:



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"; };


I understand that this is caused by the fact that there is implicit conversion from lambda to std::function and then implicit conversion from std::function to Caller, and we cannot perform 2 conversions at the same time.


Is it somehow possible to make syntax Class object = lambda; work? I'm asking because I played recently with writing my own small testing framework for educational reasons and I thought that this:



UNIT_TEST(test_name) {
// test content
};


is much more elegant than



UNIT_TEST_BEGIN(test_name)
// unit test
UNIT_TEST_END()


The former can be achieved with lambdas passed into the UnitTest constructor. But with problem that I described I had to use dirty workaround like:



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


and it doesn't look elegant at all. But even if this can be done without lambdas I'm still intrigued whether Class object = lamda; syntax can be achieved.


Aucun commentaire:

Enregistrer un commentaire