无需模板构建std::function包装类WrapperFunction的技术问询
Absolutely, this is totally doable! Let's walk through how to build your WrapperFunction class that decomposes and stores the core parts of a std::function—return type, arguments, and the callable itself—without requiring the wrapper to be a template class upfront.
Core Concept: Type Extraction + Type Erasure
First, we need two key pieces to make this work:
- A way to extract the return type and argument types from a given
std::function(we'll use template specialization for this). - A way to store any type of
std::functionin a non-template class (we'll usestd::anyfor safe type erasure, available in C++17+).
Step 1: Function Traits for Type Extraction
We'll create a helper template to pull out the return type and argument types from a std::function:
#include <functional> #include <tuple> #include <typeinfo> #include <any> // Helper traits to extract type info from std::function template<typename Func> struct FunctionTraits; // Specialization for std::function<R(Args...)> template<typename R, typename... Args> struct FunctionTraits<std::function<R(Args...)>> { using ReturnType = R; using ArgsTuple = std::tuple<Args...>; // Optional: Get individual argument types by index template<std::size_t N> using ArgType = std::tuple_element_t<N, ArgsTuple>; };
Step 2: Implement the WrapperFunction Class
This class will accept any std::function in its constructor, store the callable, and record the return/argument type info. We'll add getter methods to retrieve all stored data:
class WrapperFunction { public: // Constructor: Accept any std::function and store its components template<typename R, typename... Args> WrapperFunction(std::function<R(Args...)> func) : m_stored_func(std::move(func)), m_return_type(&typeid(R)), m_args_type(&typeid(typename FunctionTraits<decltype(func)>::ArgsTuple)) {} // Getter: Retrieve the stored callable (returns std::any for type erasure) const std::any& get_function() const { return m_stored_func; } // Getter: Get type info for the return type const std::type_info& get_return_type() const { return *m_return_type; } // Getter: Get type info for the arguments (as a tuple of argument types) const std::type_info& get_args_type() const { return *m_args_type; } // Helper: Safely cast the stored function back to its original std::function type // Throws std::bad_any_cast if the type doesn't match template<typename R, typename... Args> std::function<R(Args...)> get_as() const { return std::any_cast<std::function<R(Args...)>>(m_stored_func); } private: std::any m_stored_func; // Stores the callable (any std::function type) const std::type_info* m_return_type; // Type info for the return value const std::type_info* m_args_type; // Type info for the argument tuple };
Step 3: Example Usage
Let's test the wrapper with different functions/lambdas to see it in action:
#include <iostream> #include <string> int main() { // Wrap a simple addition lambda auto add = [](int a, int b) { return a + b; }; std::function<int(int, int)> add_func = add; WrapperFunction add_wrapper(add_func); // Check type info (note: type names are compiler-specific) std::cout << "Return type: " << add_wrapper.get_return_type().name() << "\n"; std::cout << "Args type: " << add_wrapper.get_args_type().name() << "\n"; // Retrieve and call the function auto retrieved_add = add_wrapper.get_as<int, int, int>(); std::cout << "5 + 7 = " << retrieved_add(5, 7) << "\n\n"; // Wrap a void-returning lambda auto greet = [](const std::string& name) { std::cout << "Hello, " << name << "!\n"; }; std::function<void(const std::string&)> greet_func = greet; WrapperFunction greet_wrapper(greet_func); auto retrieved_greet = greet_wrapper.get_as<void, const std::string&>(); retrieved_greet("Alice"); return 0; }
Key Notes
- C++ Version:
std::anyrequires C++17 or later. If you're stuck on an older version, you can use avoid*with a custom deleter and type checker, butstd::anyis far safer. - Type Safety: When using
get_as(), you must specify the exact return type and argument types. Mismatched types will throw astd::bad_any_castexception. - Type Info: The
name()method ofstd::type_inforeturns a compiler-specific string (not human-readable in all cases), but you can use==to compare types for equality. - Extensibility: If you need more granular argument info (like number of arguments or individual argument types), you can extend the
FunctionTraitsto store that data inWrapperFunction.
内容的提问来源于stack exchange,提问作者Squerut

