Programing

기본 클래스로서의 Lambda 함수

lottogame 2020. 11. 6. 07:45
반응형

기본 클래스로서의 Lambda 함수


Lambda를 가지고 놀면서 완전히 이해하지 못하는 흥미로운 동작을 발견했습니다.

나는이 Supose struct Overload2 개 템플릿 매개 변수에서 파생 있음을, 그리고이 using F1::operator();절을.

이제 두 펑터에서 파생 된 경우 F1의 operator ()에만 액세스 할 수 있습니다 (예상대로).

두 개의 Lambda 함수에서 파생 된 경우 더 이상 사실이 아닙니다. F2에서도 operator ()에 액세스 할 수 있습니다.

#include <iostream>

// I compiled with g++ (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8)
//
// g++ -Wall -std=c++11 -g main.cc
// g++ -Wall -std=c++11 -DFUNCTOR -g main.cc
// 
// or clang clang version 3.3 (tags/RELEASE_33/rc2)
// 
// clang++ -Wall -std=c++11 -g main.cc
// clang++ -Wall -std=c++11 -DFUNCTOR -g main.cc
// 
// on a Linux localhost.localdomain 3.9.6-200.fc18.i686 #1 SMP Thu Jun 13 
// 19:29:40 UTC 2013 i686 i686 i386 GNU/Linux box


struct Functor1
{
    void operator()() { std::cout << "Functor1::operator()()\n"; }
};

struct Functor2
{
    void operator()(int) { std::cout << "Functor2::operator()(int)\n"; }
};

template <typename F1, typename F2>
struct Overload : public F1, public F2
{
    Overload()
        : F1()
        , F2() {}

    Overload(F1 x1, F2 x2)
        : F1(x1)
        , F2(x2) {}

    using F1::operator(); 
};

template <typename F1, typename F2>
auto get(F1 x1, F2 x2) -> Overload<F1, F2>
{
   return Overload<F1, F2>(x1, x2);
}


int main(int argc, char *argv[])
{
    auto f = get(Functor1(), Functor2());

    f();
#ifdef FUNCTOR
    f(2); // this one doesn't work IMHO correctly
#endif

    auto f1 = get(
                  []() { std::cout << "lambda1::operator()()\n"; },
                  [](int) { std::cout << "lambda2::operator()(int)\n"; }
                  );
    f1();
    f1(2); // this one works but I don't know why


  return 0;
}

표준은 다음과 같이 명시합니다.

람다 식의 형식 (클로저 개체의 형식이기도 함)은 고유하고 명명되지 않은 비 공용체 클래스 형식입니다.

따라서 모든 Lambda의 유형은 고유해야합니다.

나는 이것이 왜 그렇게되었는지 설명 할 수 없다 : 누구든지 이것에 대해 약간의 빛을 비출 수 있습니까?


뿐만 아니라 operator()람다에 의해 정의 된 클래스는 (적절한 상황에서) 함수에 대한 포인터로의 변환을 제공 할 수 있습니다. 상황 (또는 적어도 기본 상황)은 람다가 아무것도 캡처 할 수 없다는 것입니다.

캡처를 추가하는 경우 :

auto f1 = get(
              []() { std::cout << "lambda1::operator()()\n"; },
              [i](int) { std::cout << "lambda2::operator()(int)\n"; }
              );
f1();
f1(2);

... 로의 변환 pointer to function이 더 이상 제공되지 않으므로 위의 코드를 컴파일하려고하면 예상했던 오류가 발생합니다.

trash9.cpp: In function 'int main(int, char**)':
trash9.cpp:49:9: error: no match for call to '(Overload<main(int, char**)::<lambda()>, main(int, char**)::<lambda(int)> >) (int)'
trash9.cpp:14:8: note: candidate is:
trash9.cpp:45:23: note: main(int, char**)::<lambda()>
trash9.cpp:45:23: note:   candidate expects 0 arguments, 1 provided

람다는 functor 클래스를 생성합니다.

실제로 람다에서 파생되고 다형성 람다를 가질 수 있습니다!

#include <string>
#include <iostream>

int main()
{
    auto overload = make_overload(
        [](int i)          { return '[' + std::to_string(i) + ']'; },
        [](std::string s)  { return '[' + s + ']'; },
        []                 { return "[void]"; }
        );

    std::cout << overload(42)              << "\n";
    std::cout << overload("yay for c++11") << "\n";
    std::cout << overload()                << "\n";
}

인쇄물

[42]
[yay for c++11]
[void]

어떻게?

template <typename... Fs>
   Overload<Fs...> make_overload(Fs&&... fs)
{
    return { std::forward<Fs>(fs)... };
}

물론 ... 이것은 여전히 ​​마법을 숨 깁니다. Overload모든 람다에서 '마법처럼'파생되고 해당 하는 클래스를 노출하는 클래스입니다 operator().

#include <functional>

template <typename... Fs> struct Overload;

template <typename F> struct Overload<F> {
    Overload(F&& f) : _f(std::forward<F>(f)) { }

    template <typename... Args>
    auto operator()(Args&&... args) const 
    -> decltype(std::declval<F>()(std::forward<Args>(args)...)) {
        return _f(std::forward<Args>(args)...);
    }

  private:
    F _f;
};

template <typename F, typename... Fs>
   struct Overload<F, Fs...> : Overload<F>, Overload<Fs...>
{
    using Overload<F>::operator();
    using Overload<Fs...>::operator();

    Overload(F&& f, Fs&&... fs) :  
        Overload<F>(std::forward<F>(f)),
        Overload<Fs...>(std::forward<Fs>(fs)...)
    {
    }
};

template <typename... Fs>
   Overload<Fs...> make_overload(Fs&&... fs)
{
    return { std::forward<Fs>(fs)... };
}

Coliru에서 라이브 보기

참고 URL : https://stackoverflow.com/questions/18432260/lambda-functions-as-base-classes

반응형