Overloading lambda's in C++11

Door .oisyn op zaterdag 02 februari 2013 01:56 - Reacties (3)
Categorie: Random code farts, Views: 2.059

Een C++ proposal dat lambda expressions generiek maakt (ofwel, templated arguments), N3418, bespreekt toevallig ook een techniek om lambda's te overloaden die momenteel in C++11 al werkt en die ik jullie niet wilde laten ontgaan. Leipe shit, ouwe!


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
template<class F1class F2>
struct overloaded : F1F2
{
    overloaded(F1 x1F2 x2) : F1(x1), F2(x2) {}
    using F1::operator();
    using F2::operator();
};
 
template<class F1class F2>
overloaded<F1F2overload(F1 f1F2 f2)
{
    return overloaded<F1F2>(f1f2);
}

int main()
{
    auto f = overload
    (
        [](int i) { std::cout << "int" << std::endl; }
        [](float f) { std::cout << "float" << std::endl; }
    );

    f(34);
    f(34.f);
}


Lambda's zijn stiekem gewoon classes met een operator(). Je kunt er dus van overerven, en bovenstaande truc werkt dan ook door een class van twee lambda's over te laten erven en beide operator()'s in de huidige scope te stoppen dmv een using declaration.

Bovenstaande code is ook uit te breiden zodat hij werkt met een arbitrair aantal lambda's, en daarnaast ook met losse functies en pointer-to-members:


C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <iostream>
#include <type_traits>
#include <functional>

template<class... Fn>
struct overloaded_function;

template<class F1class F2>
struct overloaded_function<F1F2> : F1F2
{
   overloaded_function(F1 f1F2 f2) : F1(f1), F2(f2) { }

    using F1::operator();
    using F2::operator();
};

template<class F1class F2class... Fn>
struct overloaded_function<F1F2Fn...> : F1overloaded_function<F2Fn...>
{
    overloaded_function(F1 f1F2 f2Fn... fn) : F1(f1), overloaded_function<F2Fn...>(f2fn...) { }

    using F1::operator();
    using overloaded_function<F2Fn...>::operator();
};

template<class Rclass... Args>
struct function_wrapper
{
    function_wrapper(R (*f)(Args...)) : func(f) { }
    
    R operator()(Args... args)
    {
        return func(args...);
    }

    R (*func)(Args...);
};

template<class Tbool B = std::is_member_pointer<T>::value>
struct callable_wrapper_helper
{
    typedef T type;
};

template<class T>
struct callable_wrapper_helper<Ttrue>
{
    typedef decltype(std::mem_fn(T())) type;
};

template<class Rclass... Args>
struct callable_wrapper_helper<R (*)(Args...), false>
{
    typedef function_wrapper<RArgs...> type;
};

template<class Tstruct callable_wrapper_type
{
    typedef typename callable_wrapper_helper<typename std::remove_reference<T>::type>::type type;
};

template<class T>
typename callable_wrapper_type<T>::type wrap_callable(T t)
{
   return typename callable_wrapper_type<T>::type(t);
}

template<class... Fn>
overloaded_function<typename callable_wrapper_type<Fn>::type...> overload(Fn... fn)
{
    return { wrap_callable(fn)... };
}

const char * foo(std::nullptr_t) { return "nullptr"; }

int main()
{
    auto f = overload
    (
        [](int i) { return "int"; },
        [](float f) { return "float"; },
        [](const char * s) { return "const char*"; },
        foo,
        &std::string::c_str
    );

    std::string s("std::string");

    std::cout << f(34) << std::endl;
    std::cout << f(34.f) << std::endl;
    std::cout << f("34") << std::endl;
    std::cout << f(nullptr) << std::endl;
    std::cout << f(&s) << std::endl;
}


Werkt in zowel VC++ met November '12 CTP compiler als in GCC 4.7.2

Volgende: A more useful bind() for Javascript 01-'13 A more useful bind() for Javascript

Reacties


Door Tweakers user H!GHGuY, zaterdag 02 februari 2013 09:19

Ik neem aan dat het eerste voorbeeld, als je lambda's vervangt door functors, ook al werkt in C++03, right?

Bij het tweede voorbeeld zal dit iets moeilijker (lees veel meer code) zijn door de variadic templates.

Door Tweakers user Caelorum, zaterdag 02 februari 2013 11:10

Leuke artikelen telkens :) Ik moest wel eerst een paar keer de code doorlezen voordat ik het snapte hoor ^^
Ben je van plan om vaker wat te posten?

Door Tweakers user .oisyn, zaterdag 02 februari 2013 23:05

H!GHGuY schreef op zaterdag 02 februari 2013 @ 09:19:
Ik neem aan dat het eerste voorbeeld, als je lambda's vervangt door functors, ook al werkt in C++03, right?
Klopt inderdaad.
Caelorum schreef op zaterdag 02 februari 2013 @ 11:10:
Ben je van plan om vaker wat te posten?
Op zich wel :). Ik loop al jaren rond met het idee om af en toe wat te posten. Normaal plaats ik dit soort onzin in het devschuur coffee corner topic, maar toen dacht ik bij mezelf, waarom er niet gewoon over bloggen.

Wat ik in ieder geval wel wil doen is af en toe wat updates plaatsen rondom de nieuwste ontwikkelingen op het gebied van C++ standaardisatie.

Reageren is niet meer mogelijk