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