2016-07-15 8 views
4

を通じて過負荷にファンクタを実現:は、いくつかの既存のファンクタ所定の組成物

struct incr { 
    int operator()(int x) const { return x + 1; } 
}; 

struct rep_str { 
    std::string operator()(const std::string& s) const { return s + s; } 
}; 

それはこのような何かを達成することが可能だ場合、私は思ったんだけど:

auto f = overload<fa, fb, fc, ...>(); 
// or... 
auto g = overload<fa, overload<fb, overload<fc, ...>>>(); 

auto f = overload<incr, rep_str>(); 
f(1);  // returns 2 
f("hello"); // returns "hellohello" 

複数のオーバーロードは次のようになります。

SFINAEをstd::result_of_tなどで使用していると思われます。 t、しかし、どのように考え出していない。ただ、すべての引数を継承し、基底クラスからoperator()に持参する使用して、宣言を使用します。

+0

3つのオーバーロードの構成は、この構文でどのように機能しますか? 'overload >'?または 'overload < X, Y, Z >'? –

+0

@XerenNarcy私は両方のデザインがうまくいくと思います。 'overload >'はネストされたペアのように見えますが、 'overload 'はタプルを思い出させます(overload_catなど)。 –

+1

標準にそのようなものを得るための[proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0051r0.pdf)さえあります。それはC++ 17の準備ができていませんでしたが、C++ 20のための準備が整いました。 [参考実装]もあります(https://github.com/viboes/tags/blob/master/include/yafpl/v1/functional/overload.hpp) –

答えて

8

あなたも凝っは必要ありません。

template <class... Ts> 
struct overload {}; // only used for empty pack 

template <class T> 
struct overload<T> : private T { 
    using T::operator(); 
}; 

template <class T1, class T2, class... Ts> 
struct overload<T1, T2, Ts...> : private T1, overload<T2, Ts...> { 
    using T1::operator(); 
    using overload<T2, Ts...>::operator(); 
}; 
+0

うわー、私は実際にこれが本当にだとは思わなかったできない。印象的な。 –

+1

さらに、解決順序が明確に定義されています。 –

2

ブライアンの答えは、IMHOより良いですが、:あなたはそうは次のように、再帰的なアプローチを使用する必要があるのでしかし、可変長の場合には、あなたは、宣言を使用してにパックの拡張を持つことができません私はそれに取り組んでいるので、ここでは私のもの:

#include <type_traits> 
#include <utility> 

template <typename... Fns> 
struct overload; 

template <typename Fn, typename... Fns> 
struct overload<Fn, Fns...> 
{ 
    template <typename... T> 
    std::result_of_t<Fn(T...)> operator()(T && ... args) const { 
     return Fn()(std::forward<T>(args)...); 
    } 

    using next = overload<Fns...>; 

    template <typename... T> 
    std::result_of_t<next(T...)> operator()(T && ... args) const { 
     return next()(std::forward<T>(args)...); 
    } 
}; 
0

これは、テンプレートの特殊化を使用して行うことができます。

#include <string> 
#include <iostream> 
template <typename...Args> 
struct overload{ 

}; 
template <> struct overload<int>{ 
    int operator()(int x) const { return x + 1; } 
}; 
template <> struct overload< std::string>{ 
    std::string operator()(const std::string& s) const { return s + s; } 
}; 
template <typename...Args > 
auto f(Args...arg){ 
    overload<Args...> func; 
    return func(arg...); 
} 
int main() 
{ 
    std::cout << f(3) << std::endl << f(std::string("Hello"));  
} 

注:詳細GE @Brianによるとmd5i @ 2つの答えネラルとエレガントで完璧で、これよりも優れています。

関連する問題