c++ 如何声明一个有N个double类型参数的函数?

wz1wpwve  于 2023-08-09  发布在  其他
关注(0)|答案(6)|浏览(117)

我想有一个类模板能够存储一个函数对象接受正是“N”双参数。这个伪代码使用了一个不存在的std::repeated_type函数模板来解决这个问题,并说明了预期的用法:

  1. template<int N>
  2. class FunctionHolder {
  3. public:
  4. using function_type = std::function<int(std::repeated_type<double, N> args)>;
  5. FunctionHolder(const function_type& arg): m_func(arg) {}
  6. private:
  7. const function_type& m_func;
  8. };
  9. int my_func(double arg1, double arg2);
  10. void main() {
  11. FunctionHolder<2> my_holder(my_func);
  12. }

字符串
我希望代码最大程度地简单和可读,所以即使我模糊地理解我可以使用std::integer_sequence和helper类模板来缝合解决方案,但我不相信我的解决方案足够简单。

jfewjypa

jfewjypa1#

您可以递归地将函数参数添加到模板列表中:

  1. template <typename Ret, std::size_t N, typename Type, typename... T>
  2. struct RepeatFunctionArgType {
  3. static auto fnt() {
  4. if constexpr (sizeof...(T) >= N) {
  5. return std::function<Ret(T...)>{};
  6. } else {
  7. return RepeatFunctionArgType<Ret, N, Type, Type, T...>::fnt();
  8. }
  9. }
  10. using type = decltype(fnt());
  11. };

字符串
这可以被访问为RepeatFunctionArgType<int,3,double>::type

  1. static int foo(double,double,double) {return 0;}
  2. int main() {
  3. RepeatFunctionArgType<int,3,double>::type fn = foo;
  4. }

展开查看全部
b4wnujal

b4wnujal2#

你可以在未求值的上下文中使用lambda来获取其返回类型:

  1. using function_type =
  2. decltype([]<std::size_t... I>(std::index_sequence<I...>) {
  3. // expand to as many `double`s as there are `I`s:
  4. return std::function<int(decltype((static_cast<void>(I)), double{})...)>{};
  5. }(std::make_index_sequence<N>{}));

字符串
交替地

  1. using function_type =
  2. decltype([]<std::size_t... I>(std::index_sequence<I...>)
  3. // expand to as many `double`s as there are `I`s:
  4. -> std::function<int(decltype((static_cast<void>(I)), double{})...)> {
  5. // this space intentionally left blank
  6. }(std::make_index_sequence<N>{}));


A more generic solution adapted from 康桓瑋's code in the comments could look like this:

  1. template <std::size_t, class T>
  2. using identity = T;
  3. template <class R, class Arg, std::size_t N>
  4. struct repeated_arg_func {
  5. using type =
  6. typename decltype([]<std::size_t... Is>(std::index_sequence<Is...>)
  7. -> std::type_identity<R(identity<Is, Arg>...)> {
  8. }(std::make_index_sequence<N>{}))::type;
  9. };
  10. template <class R, class Arg, std::size_t N>
  11. using repeated_arg_func_t = typename repeated_arg_func<R, Arg, N>::type;
  12. template <int N, class ArgType, class RetType>
  13. class FunctionHolder {
  14. public:
  15. using signature = repeated_arg_func_t<RetType, ArgType, N>;
  16. using function_type = std::function<signature>;
  17. FunctionHolder(const function_type& arg) : m_func(arg) {}
  18. private:
  19. function_type m_func;
  20. };


旁注:const function_type&成员不是一个好主意,除非您实际提供的std::function<...>FunctionHolder寿命长。您的示例创建了一个临时std::function<...>,该临时std::function<...>将在FunctionHolder的构造完成后立即过期。
我建议将其设为常规非参考成员:

  1. function_type m_func;

展开查看全部
kxkpmulp

kxkpmulp3#

使用helper class template,它可能是

  1. template <std::size_t, typename T>
  2. using always_t = T;
  3. template<typename Seq> class FunctionHolderImpl;
  4. template<std::size_t... Is>
  5. class FunctionHolderImpl<std::index_sequence<Is...>> {
  6. public:
  7. using function_type = std::function<int(always_t<Is, double>... args)>;
  8. FunctionHolder(const function_type& arg): m_func(arg) {}
  9. private:
  10. function_type m_func;
  11. };
  12. template <std::size_t N>
  13. using FunctionHolder = FunctionHolderImpl<std::make_index_sequence<N>>;

字符串

展开查看全部
x0fgdtte

x0fgdtte4#

下面是一个C++17的解决方案,你不需要在main()中显式地专门化保持器,也不需要显式地声明参数的数量。

  1. #include <type_traits>
  2. #include <functional>
  3. #include <iostream>
  4. // Some helpers to check if all arguments of the function have the same argument type
  5. template<typename arg_t, typename... args_t>
  6. static constexpr bool all_same_as_first()
  7. {
  8. return std::conjunction_v<std::is_same<arg_t, args_t>...>;
  9. };
  10. template<typename... args_t>
  11. static constexpr bool all_same()
  12. {
  13. // Specialized logic for 0 or 1 argument, consider them the same.
  14. if constexpr (sizeof...(args_t) < 2ul)
  15. {
  16. return true;
  17. }
  18. else
  19. {
  20. return all_same_as_first<args_t...>();
  21. }
  22. }
  23. // The actual function holder
  24. // it also needs specialization on the return value type
  25. template<typename retval_t, typename... args_t>
  26. class FunctionHolder
  27. {
  28. public:
  29. static_assert(all_same<args_t...>()); // check condition that all arguments are of same type
  30. // construct
  31. explicit FunctionHolder(std::function<retval_t(args_t...)> fn) :
  32. m_fn{ fn }
  33. {
  34. }
  35. // allow calls to be made through the holder directly
  36. retval_t operator()(args_t&&...args)
  37. {
  38. return m_fn(std::forward<args_t>(args)...);
  39. }
  40. private:
  41. std::function<retval_t(args_t...)> m_fn;
  42. };
  43. // helper for type deduction of std::function type
  44. template<typename fn_t>
  45. auto make_holder(fn_t fn)
  46. {
  47. std::function std_fn{fn};
  48. return FunctionHolder{ std_fn };
  49. }
  50. // your function
  51. int my_func(double arg1, double arg2)
  52. {
  53. return static_cast<int>(arg1+arg2);
  54. }
  55. // And the usage
  56. int main()
  57. {
  58. auto holder = make_holder(my_func);
  59. auto retval = holder(1.0, 2.0);
  60. return 0;
  61. }

字符串

展开查看全部
5cnsuln7

5cnsuln75#

像这样的东西怎么样:

  1. #include <functional>
  2. #include <type_traits>
  3. template<int N, typename...Args>
  4. struct FunctionHolder {
  5. public:
  6. using function_type = std::function<int(Args...)>;
  7. static_assert(sizeof...(Args) == N);
  8. static_assert((std::is_same_v<Args, double> && ...), "");
  9. FunctionHolder(const function_type& arg): m_func(arg) {}
  10. const function_type m_func;
  11. };
  12. template<int N, typename...Args>
  13. auto makeFunctionHolder(int(*f)(Args...))
  14. {
  15. return FunctionHolder<N, Args...>(f);
  16. }
  17. int my_func(double arg1, double arg2)
  18. {
  19. return arg1+arg2;
  20. }
  21. int my_func2(double arg1, char arg2)
  22. {
  23. return arg1+arg2;
  24. }
  25. int my_func3(double arg1)
  26. {
  27. return arg1;
  28. }
  29. int main() {
  30. auto h1 = makeFunctionHolder<2>(my_func);
  31. //auto h2 = makeFunctionHolder<2>(my_func2); //should fail due to types
  32. // auto h3 = makeFunctionHolder<2>(my_func3); //should fail to number
  33. auto h3 = makeFunctionHolder<1>(my_func3); //should pass
  34. return h1.m_func(4.0, 5.0);
  35. }

字符串
https://godbolt.org/z/cjEq4s7Ef
当然,它使用工厂函数,但也可以使用演绎指南来实现。一切都是为了测试而公开的,根据你的喜好调整它。

展开查看全部
mepcadol

mepcadol6#

可以使用std::array<double, N>作为函数的参数
(而不是单独的double参数):

  1. #include <array>
  2. #include <functional>
  3. template<int N>
  4. class FunctionHolder {
  5. public:
  6. //--------------------------------------vvvvvvvvvvvvvvvvvvvvv--------
  7. using function_type = std::function<int(std::array<double, N> args)>;
  8. FunctionHolder(const function_type& arg) : m_func(arg) {}
  9. private:
  10. const function_type& m_func;
  11. };
  12. //----------vvvvvvvvvvvvvvvvvvvvv-------
  13. int my_func(std::array<double, 2> arg2) {
  14. return 0;
  15. }
  16. int main() {
  17. FunctionHolder<2> my_holder(my_func);
  18. }

字符串
Demo - Godbolt

展开查看全部

相关问题