通过组合实现函子重载

Achieve functor overloading through composition

本文关键字:重载 实现 组合      更新时间:2023-10-16

给定一些现有的函子:

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<incr, rep_str>();
f(1);        // returns 2
f("hello");  // returns "hellohello"

多个重载可能如下所示:

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

我想也许将 SFINAE 与 std::result_of_t 或类似的东西一起使用,但还没有弄清楚如何。

你不需要任何太花哨的东西:只需从所有参数继承并使用 using-声明从基类引入operator()。但是,在可变参数的情况下,你不能在 using-声明中使用包扩展,所以你必须使用递归方法,如下所示:

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();
};

恕我直言,布莱恩的答案更好,但既然我努力了,这是我的:

#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)...);
    }
};

可以使用模板专用化来完成:

#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"));    
}

注:@Brian和@md5i两个答案比这更一般、更优雅、更完美、更好。