make_overloadを書いた

きっかけは@sscriskさんがTwitterで次のようなおもしろコードを貼っていたことです。
http://melpon.org/wandbox/permlink/vfXMZR8lGs78NGs6

 auto f = make_overload(
      [](int i){ std::cout << "int: " << i << '\n'; },
      [](double d){ std::cout << "double: " << d << '\n'; }
 );

f(10);
f(9.99);

このようにオーバーロードを実現した関数オブジェクトを作ることが目的です。 先urlの実装ではgccでは動作せず、clangだと動作するのですが、どうもStackOverflowの情報と規格によるとambiguousとするgccの方が正しいようなのでこの方針ではうまくいきません。
http://stackoverflow.com/questions/5368862/why-do-multiple-inherited-functions-with-same-name-but-different-signatures-not

曖昧性をなくすには適切にusingしてやる必要があるようなのですが可変長引数Fに対して

using F::operator()...;

とは書けないので、方針を変えて再帰的に継承してusingしてやったところうまくいったようです。

template<class F1, class... Fs>
struct overload : F1, overload<Fs...>
{
    using F1::operator();
    using overload<Fs...>::operator();
    overload(F1 f1, Fs... fs) : F1(f1), overload<Fs...>(fs...) {}
};

template<class F1>
struct overload<F1> : F1
{
    using F1::operator();
    overload(F1 f1) : F1(f1) {}
};

#include<iostream>

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

struct b {
    void operator()(double d) { std::cout << "double: " << d << '\n'; }
};

struct c {
    void operator()(char c) { std::cout << "char: " << c << '\n'; }
};

template<class... Fs>
auto make_overload(Fs... fs) {
    return overload<Fs...>(fs...);
}

int main()
{
    auto f = make_overload(a{}, b{}, c{}, [](int i, char c) { std::cout << "int, char: " << i << c << '\n'; });
    f(10);
    f(9.99);
    f('a');
    f(1, 'a');
}

http://melpon.org/wandbox/permlink/XyskzfxVJiyo5vst

しかしテンプレートパラメータパックを展開して一気に多重継承するという前者の発想は面白いですね。思いつきませんでした。