我是元编程的新手。第二个参数将与传递的功能参数相同。我想从Func
推论出第二种参数类型,在这里需要帮助。
template<typename Func>
void execute(Func func, decltype(Func) t) {
std::cout << func(t) << std::endl;
}
int main() {
std::function<int(float)> func1 = [](float f) { return int(f); };
execute(func1,1.5);
return 0;
}
这可行,但是我不想声明其他typenameme T
,因为该信息已经在Func
中提供了,所以为什么不推论。
template<typename Func, typename T>
void execute(Func func, T t) {
std::cout << func(t) << std::endl;
}
答案 0 :(得分:3)
在您的示例中,无需知道确切的参数类型,因此,最简单的解决方案是使用可变参数模板。只需获取一个参数包并转发它们:
template<typename Func, typename... Args>
void execute(Func func, Args&&... a) {
std::cout << func(std::forward<Args>(a)...) << std::endl;
}
int main() {
auto func1 = [](float f) { return int { f }; };
execute(func1, 1.5);
auto func2 = [](int i) { return float { i }; };
execute(func2, 15);
auto func3 = [](int a, int b, int c) { return a * b + c; };
execute(func3, 3, 4, 5);
return 0;
}
答案 1 :(得分:2)
我想从
Func
推论出第二种参数类型我不想声明其他
typename T
除了在binding with the argument之后将可调用对象传递给函数之外,我看不到任何简单的解决方案。
以下内容将确保您的第二个要求,而无需过多更改原始代码。
#include <functional>
#include <iostream>
template<typename Func>
void execute(Func func) {
std::cout << func() << std::endl;
}
int main()
{
auto func1 = std::bind([](float f) { return int(f); }, 2.5f);
execute(func1);
return 0;
}
答案 2 :(得分:2)
您应该不执行此操作。如果这样做,您的示例将停止工作,因为您的函数是int(float)
,但是参数是double
。
#include <functional>
#include <iostream>
template<typename Arg>
void execute(std::function<int(Arg)> func, Arg t) {
std::cout << func(t) << std::endl;
}
int main() {
std::function<int(float)> func1 = [](float f) { return int(f); };
execute(func1,1.5);
return 0;
}
这不会编译。 Live demo。
保持T参数完全正确。
答案 3 :(得分:1)
您正在寻找的是一种类型特征,该特征可以访问函数签名中使用的类型。标准库中没有这样的类型特征。因此,您要么需要使用实现一个的库,要么自己实现。
如果可以使用boost,它们将在其类型特征中完全实现此功能:https://www.boost.org/doc/libs/1_68_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html您想使用argN_type
成员来获取第N个参数的类型。
如果不能使用boost,则需要实现自己的类型特征以使参数类型可用。可能看起来像这样:
// Base case for non-function types
template<typename T>
struct func_types { };
// Case for any generic function signature
template<typename Return, typename ...Args>
struct func_types<Return(Args...)>
{
using ReturnType = Return;
using ArgsTuple = std::tuple<Args...>;
template<std::size_t N>
struct args
{
using Type = std::tuple_element_t<N, ArgsTuple>;
};
};
// Specialization for function pointers
template<typename Return, typename ...Args>
struct func_types<std::function<Return(Args...)>> : public func_types<Return(Args...)> { };
// Specialization for std::function
template<typename Return, typename ...Args>
struct func_types<std::function<Return(Args...)>> : public func_types<Return(Args...)> { };
// All further specializations for member functions,
// lambdas, etc. are left as an exercise to the reader
template<typename Func>
void execute(Func func, typename func_types<Func>::template args<0>::Type t)
{
std::cout << func(t) << std::endl;
}
This example is basically a stripped down version of this blog post。这使用了C ++ 14中添加的功能,因此您需要针对该版本或更高版本进行编译。
答案 4 :(得分:1)
这里是一个例子:
#include <tuple>
#include <type_traits>
template <typename> struct function_traits;
template <typename Function>
struct function_traits
: public function_traits<decltype(
&std::remove_reference<Function>::type::operator())> {};
template <typename ClassType, typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (ClassType::*)(Arguments...) const>
: function_traits<ReturnType (*)(Arguments...)> {};
/* support the non-const operator ()
* this will work with user defined functors */
template <typename ClassType, typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (ClassType::*)(Arguments...)>
: function_traits<ReturnType (*)(Arguments...)> {};
template <typename ReturnType, typename... Arguments>
struct function_traits<ReturnType (*)(Arguments...)> {
typedef ReturnType result_type;
using argument_tuple = std::tuple<Arguments...>;
template <std::size_t Index>
using argument = typename std::tuple_element<Index, argument_tuple>::type;
static const std::size_t arity = sizeof...(Arguments);
};
template <typename Function, std::size_t Index>
using nth_argument_type =
typename function_traits<Function>::template argument<Index>;
#include <iostream>
using namespace std;
template <typename FN>
void execute(FN func, nth_argument_type<FN,0> arg0) {
std::cout << func(arg0) << std::endl;
};
int main() {
int i = 7;
auto fn = [](int a) { return a * a; };
auto fn2 = [](int a) mutable { return a * a; };
execute(fn, 5);
execute(fn, i);
execute(fn2, 5);
execute(fn2, i);
};