我正在寻找一种实现函数类的方法
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
将在运行时使用正确数量的参数调用基础函数。
这样的事情可能吗?
答案 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;
}