Ada*_*ski 7 c++ template-meta-programming
我想要一个能够存储接受“N”个双参数的功能对象的类模板。此伪代码使用一个不存在的std::repeated_type
函数模板来解决问题并说明预期用法:
template<int N>
class FunctionHolder {
public:
using function_type = std::function<int(std::repeated_type<double, N> args)>;
FunctionHolder(const function_type& arg): m_func(arg) {}
private:
const function_type& m_func;
};
int my_func(double arg1, double arg2);
void main() {
FunctionHolder<2> my_holder(my_func);
}
Run Code Online (Sandbox Code Playgroud)
我希望代码尽可能简单且可读,因此即使我模糊地理解我可以使用 std::integer_sequence 和辅助类模板来缝合解决方案,但我不相信我的解决方案足够简单。
bit*_*ask 10
您可以递归地将函数参数添加到模板列表中:
template <typename Ret, std::size_t N, typename Type, typename... T>
struct RepeatFunctionArgType {
static auto fnt() {
if constexpr (sizeof...(T) >= N) {
return std::function<Ret(T...)>{};
} else {
return RepeatFunctionArgType<Ret, N, Type, Type, T...>::fnt();
}
}
using type = decltype(fnt());
};
Run Code Online (Sandbox Code Playgroud)
这可以作为 访问RepeatFunctionArgType<int,3,double>::type
。
static int foo(double,double,double) {return 0;}
int main() {
RepeatFunctionArgType<int,3,double>::type fn = foo;
}
Run Code Online (Sandbox Code Playgroud)
您可以在未计算的上下文中使用 lambda 来获取其返回类型:
\nusing function_type =\n decltype([]<std::size_t... I>(std::index_sequence<I...>) {\n // expand to as many `double`s as there are `I`s:\n return std::function<int(decltype((static_cast<void>(I)), double{})...)>{};\n }(std::make_index_sequence<N>{}));\n
Run Code Online (Sandbox Code Playgroud)\n或者
\nusing function_type =\n decltype([]<std::size_t... I>(std::index_sequence<I...>)\n // expand to as many `double`s as there are `I`s:\n -> std::function<int(decltype((static_cast<void>(I)), double{})...)> {\n // this space intentionally left blank\n }(std::make_index_sequence<N>{}));\n
Run Code Online (Sandbox Code Playgroud)\n根据注释中的 \xe5\xba\xb7\xe6\xa1\x93\xe7\x91\x8b\ 代码改编的更通用的解决方案可能如下所示:
\ntemplate <std::size_t, class T>\nusing identity = T;\n\ntemplate <class R, class Arg, std::size_t N>\nstruct repeated_arg_func {\n using type =\n typename decltype([]<std::size_t... Is>(std::index_sequence<Is...>)\n -> std::type_identity<R(identity<Is, Arg>...)> {\n }(std::make_index_sequence<N>{}))::type;\n};\n\ntemplate <class R, class Arg, std::size_t N>\nusing repeated_arg_func_t = typename repeated_arg_func<R, Arg, N>::type;\n\ntemplate <int N, class ArgType, class RetType>\nclass FunctionHolder {\npublic:\n using signature = repeated_arg_func_t<RetType, ArgType, N>;\n using function_type = std::function<signature>;\n FunctionHolder(const function_type& arg) : m_func(arg) {}\n\nprivate:\n function_type m_func;\n};\n
Run Code Online (Sandbox Code Playgroud)\n旁注:该const function_type&
成员不是一个好主意,除非您实际上提供了一个std::function<...>
比您的FunctionHolder
. 您的示例创建了一个临时对象std::function<...>
,该临时对象将在构建FunctionHolder
完成后立即过期。
我建议将其设为常规非参考成员:
\nfunction_type m_func;\n
Run Code Online (Sandbox Code Playgroud)\n
使用辅助类模板,可能是
template <std::size_t, typename T>
using always_t = T;
template<typename Seq> class FunctionHolderImpl;
template<std::size_t... Is>
class FunctionHolderImpl<std::index_sequence<Is...>> {
public:
using function_type = std::function<int(always_t<Is, double>... args)>;
FunctionHolder(const function_type& arg): m_func(arg) {}
private:
function_type m_func;
};
template <std::size_t N>
using FunctionHolder = FunctionHolderImpl<std::make_index_sequence<N>>;
Run Code Online (Sandbox Code Playgroud)
这是一个 C++17 解决方案,您不必在 main() 中显式专门化持有者,也不必显式声明参数的数量。
#include <type_traits>
#include <functional>
#include <iostream>
// Some helpers to check if all arguments of the function have the same argument type
template<typename arg_t, typename... args_t>
static constexpr bool all_same_as_first()
{
return std::conjunction_v<std::is_same<arg_t, args_t>...>;
};
template<typename... args_t>
static constexpr bool all_same()
{
// Specialized logic for 0 or 1 argument, consider them the same.
if constexpr (sizeof...(args_t) < 2ul)
{
return true;
}
else
{
return all_same_as_first<args_t...>();
}
}
// The actual function holder
// it also needs specialization on the return value type
template<typename retval_t, typename... args_t>
class FunctionHolder
{
public:
static_assert(all_same<args_t...>()); // check condition that all arguments are of same type
// construct
explicit FunctionHolder(std::function<retval_t(args_t...)> fn) :
m_fn{ fn }
{
}
// allow calls to be made through the holder directly
retval_t operator()(args_t&&...args)
{
return m_fn(std::forward<args_t>(args)...);
}
private:
std::function<retval_t(args_t...)> m_fn;
};
// helper for type deduction of std::function type
template<typename fn_t>
auto make_holder(fn_t fn)
{
std::function std_fn{fn};
return FunctionHolder{ std_fn };
}
// your function
int my_func(double arg1, double arg2)
{
return static_cast<int>(arg1+arg2);
}
// And the usage
int main()
{
auto holder = make_holder(my_func);
auto retval = holder(1.0, 2.0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
470 次 |
最近记录: |