函数类在运行时接受来自容器的可变数量的参数

时间:2013-09-07 08:56:17

标签: c++ function

我正在寻找一种实现函数类的方法

template<class ValueType>
class Function { ... };

可以使用函数指针(或函子)构造,该函数指针接受ValueType类型的任意数量的参数并返回ValueType。例如,给定这些功能:

double foo(double);
double bar(double, double);
int    baz(double, int);

可以使用Function<double>foo构建bar对象,但不能构建baz

然后,给定call(或迭代器)的容器,成员函数ValueType将在运行时使用正确数量的参数调用基础函数。

这样的事情可能吗?

2 个答案:

答案 0 :(得分:3)

确实有可能,你只需要“递归地”从容器中解压缩参数并将它们传递给最深层次的函数:

#include <cstddef>
#include <utility>
#include <stdexcept>
#include <functional>
#include <type_traits>
#include <vector>
#include <iostream>

namespace detail {
    template <std::size_t argument_count>
    struct arguments_unpacker {
        template <typename Type, typename Function, typename InputIterator, typename... UnpackedArguments>
        static Type unpack(Function&& function, InputIterator arguments_begin, InputIterator arguments_end, UnpackedArguments&&... unpacked_arguments) {
            if (arguments_begin == arguments_end) {
                throw std::invalid_argument("Not enough arguments.");
            }
            return arguments_unpacker<argument_count - 1>::template unpack<Type>(std::forward<Function>(function), std::next(arguments_begin), arguments_end, std::forward<UnpackedArguments>(unpacked_arguments)..., *arguments_begin);
        }
    };

    template <>
    struct arguments_unpacker<0> {
        template <typename Type, typename Function, typename InputIterator, typename... UnpackedArguments>
        static Type unpack(Function&& function, InputIterator arguments_begin, InputIterator arguments_end, UnpackedArguments&&... unpacked_arguments) {
            if (arguments_begin != arguments_end) {
                throw std::invalid_argument("Too many arguments.");
            }
            return function(std::forward<UnpackedArguments>(unpacked_arguments)...);
        }
    };

    template <typename MemberFunction>
    struct member_function_arity;

    template <typename Result, typename Class, typename... Arguments>
    struct member_function_arity<Result(Class::*)(Arguments...)> {
        static constexpr std::size_t value = sizeof...(Arguments); 
    };

    template <typename Result, typename Class, typename... Arguments>
    struct member_function_arity<Result(Class::*)(Arguments...) const> {
        static constexpr std::size_t value = sizeof...(Arguments); 
    };

    template <typename Function>
    struct function_arity : member_function_arity<decltype(&Function::operator())> {};

    template <typename Result, typename... Arguments>
    struct function_arity<Result(*)(Arguments...)> {
        static constexpr std::size_t value = sizeof...(Arguments);  
    };

    template <typename Result, typename... Arguments>
    struct function_arity<std::function<Result(Arguments...)>> {
        static constexpr std::size_t value = sizeof...(Arguments);  
    };
}

template <typename Type, typename InputIterator, typename Function>
std::function<Type(InputIterator, InputIterator)> variate(Function function) {
    using namespace detail;
    return [function](InputIterator arguments_begin, InputIterator arguments_end) {
        return arguments_unpacker<function_arity<Function>::value>::template unpack<Type>(function, arguments_begin, arguments_end);
    };
}

namespace demo {
    double a(double x0) {
        std::cout << "a(" << x0 << ")\n";
        return 0.0;
    }

    double b(double x0, double x1) {
        std::cout << "b(" << x0 << ", " << x1 << ")\n";
        return 0.0;
    }

    double c(double x0, double x1, double x2) {
        std::cout << "b(" << x0 << ", " << x1 << ", " << x2  << ")\n";
        return 0.0;
    }

    auto l = [](double x0) mutable {
        std::cout << "l(" << x0 << ")\n";
        return 0.0;
    };

    void run() {
        using it = std::vector<double>::const_iterator;
        auto va = variate<double, it>(&a);
        auto vb = variate<double, it>(&b);
        auto vc = variate<double, it>(&c);
        auto vl = variate<double, it>(l);
        std::vector<double> a1 = {1.0};
        std::vector<double> a2 = {1.0, 2.0};
        std::vector<double> a3 = {1.0, 2.0, 3.0};
        va(begin(a1), end(a1));
        vb(begin(a2), end(a2));
        vc(begin(a3), end(a3));
        vl(begin(a1), end(a1));
    }
}

int main()
{       
    demo::run();
    return 0;
}

请注意,这需要显式提供迭代器类型。我没有看到如果不编写某种类型的擦除any_iterator就可以解决这个问题。

答案 1 :(得分:1)

#include <functional>
#include <boost/any.hpp>


template<class ValueType>
struct Function {
    template <typename ...Args>
    Function(const std::function<ValueType(Args...)>& f)
    :   fn(f)
    {}

    template <typename ...Args>
    ValueType operator () (Args... args) {
        auto f = boost::any_cast<const std::function<ValueType(Args...)>&>(fn);
        return f(args...);
    }

    boost::any fn;
};

int a(int) { return 1; }
int b(int, double) { return 2; }

int main(int argc, char** argv)
{
    typedef std::vector<Function<int>> Functions;
    Functions functions {
        std::function<int(int)>(a),
        std::function<int(int, double)>(b)
    };
    std::cout << functions[0](1) << functions[1](1, 2.0) << std::endl;
}