C++14: Generic lambda with generic std::function as class member

*爱你&永不变心* 提交于 2019-12-01 04:21:47

There is no way you'll be able to choose between two generic lambdas at run-time, as you don't have a concrete signature to type-erase.

If you can make the decision at compile-time, you can templatize the class itself:

template <typename F>
class SomeClass
{
private:
    F fooCall;

public:
    SomeClass(F&& f) : fooCall{std::move(f)} { }
};

You can then create an helper function to deduce F:

auto makeSomeClassImpl(std::true_type) 
{
    auto l = [](auto a){ cout << a.sayHello(); };
    return SomeClass<decltype(l)>{std::move(l)};
}

auto makeSomeClassImpl(std::false_type) 
{
    auto l = [](auto b){ cout << b.sayHello(); };
    return SomeClass<decltype(l)>{std::move(l)};
}

template <bool B>
auto makeSomeClass() 
{
    return makeSomeClassImpl(std::bool_constant<B>{});
}

I was not able to store std::function<> as a generic lambda in the class directly as a member. What I was able to do was to specifically use one within the class's constructor. I'm not 100% sure if this is what the OP was trying to achieve but this is what I was able to compile, build & run with what I'm suspecting the OP was aiming for by the code they provided.

template<class>
class test {
public: // While testing I changed this to public access...
        // Could not get object below to compile, build & run
    /*template<class U = T>
    static std::function<void(U)> fooCall;*/
public:
   test();
};

template<class T>
test<T>::test() {
    // This would not compile, build & run
    // fooCall<T> = []( T t ) { std::cout << t.sayHello(); };

    // Removed the variable within the class as a member and moved it here
    // to local scope of the class's constructor
    std::function<void(T)> fooCall = []( auto a ) { std::cout << a.sayHello(); };
    T t; // created an instance of <Type T>
    fooCall(t); // passed t into fooCall's constructor to invoke the call.
}

struct A {
    std::string sayHello() { return "A say's Hello!\n"; }
};

struct B {
    std::string sayHello() { return "B say's Hello!\n"; }
};


int main() {
    // could not instantiate an object of SomeClass<T> with a member of
    // a std::function<> type that is stored by a type of a generic lambda.

    /*SomeClass<A> someA;
    SomeClass<B> someB;
    someA.foo();
    someB.foo();*/

    // Simply just used the object's constructors to invoke the locally stored lambda within the class's constructor.
    test<A> a;
    test<B> b;

    std::cout << "\nPress any key & enter to quit." << std::endl;
    char c;
    std::cin >> c;

    return 0;
}

With the appropriate headers the above as is should compile, build & run giving the output below (At least in MSVS 2017 on Windows 7 64bit did); I left comments where I ran into errors and tried multiple different techniques to achieve a working example, errors occurred as others suggested and I found even more while working with the above code. What I was able to compile, build and run came down to this simple bit of code here without the comments. I also added another simple class to show it will work with any type:

template<class>
class test {
public:
    test();
};

template<class T>
test<T>::test() {
    std::function<void( T )> fooCall = []( auto a ) { std::cout << a.sayHello(); };
    T t;
    fooCall( t );
}

struct A {
    std::string sayHello() { return "A say's Hello!\n"; }
};

struct B {
    std::string sayHello() { return "B say's Hello!\n"; }
};

struct C {    
    int sayHello() { return 100; }
};

int main() {
    test<A> testA;
    test<B> testB;
    test<C> testC;

    std::cout << "\nPress any key & enter to quit." << std::endl;
    char c;
    std::cin >> c;

    return 0;
}

Output:

A say's Hello!
B say's Hello!
100

Press any key & enter to quit

I don't know if this will help the OP directly or indirectly or not but if it does or even if it doesn't it is still something that they may come back to and build off of.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!