C++14 の Generic lambdas で SFINAE その 2

昨日書いたコードはあまり意味がなかったので簡単なラッパーを書いてラムダ式を多重定義で呼び出せるようにしてみました。
これなら SFINAE を使う意味も出てくるかな。

[ソース]

#include <iostream>
#include <string>


template<typename F1, typename F2>
struct overload_impl
    : F1, F2{
    using F1::operator();
    using F2::operator();

    overload_impl(F1 const& f1, F2 const& f2)
        : F1(f1), F2(f2){}
};


template<typename F1, typename F2>
overload_impl<
    typename std::decay<F1>::type,
    typename std::decay<F2>::type
>
overload(F1&& f1, F2&& f2){
    return {f1, f2};
}


int
main(){
    auto twice = overload(
        [](auto x)
            ->typename std::enable_if<
                std::is_integral<decltype(x)>{}, decltype(x)
            >::type{
            std::cout << x << " << 1" << std::endl;
            return x << 1;
        },
        [](auto x)
            ->typename std::enable_if<
                !std::is_integral<decltype(x)>{}, decltype(x)
            >::type{
            std::cout << x << " + " << x << std::endl;
            return x + x;
        }
    );
    
    std::cout << twice(10) << std::endl;
    std::cout << twice('!') << std::endl;
    std::cout << twice(3.14f) << std::endl;
    std::cout << twice(std::string("homu")) << std::endl;
    
    
    auto plus = overload(
        [](auto a, auto b)
        ->decltype(a + b){
            return a + b;
        },
        [](char const* str, auto b)
        ->decltype(std::string(str) + b){
            return std::string(str) + b;
        }
    );
    
    std::cout << plus(1, 2) << std::endl;
    std::cout << plus(2.5, 0.125) << std::endl;
    std::cout << plus(2.5, 5) << std::endl;
    std::cout << plus("homu", "mami") << std::endl;
    std::cout << plus("homu", std::string("mado")) << std::endl;
    // error
//  std::cout << plus(3.14f, "homu") << std::endl;
    
    return 0;
}

[出力]

10 << 1
20
! << 1
B
3.14 + 3.14
6.28
homu + homu
homuhomu
3
2.625
7.5
homumami
homumado


SFINAE は適当ですが、まぁそんな感じです。
ちなみに overload のラッパーは C++11 でも流用することは可能です。
ラムダ式か関数オブジェクトでなければ使用できませんが地味に便利。
あとこういう処理も組み込んでおくと更に便利な気がする。

[コンパイラ]

  • clang++ (LLVM) 3.4 20131004(trunk)