编写C++ Adapter类:适配函数对象/指针的返回值类型包装器
Alright, let's build this Adapter class you're asking for. The key idea is to wrap any callable (function pointers, functors, lambdas) into a type that always returns your predefined ReturnType, no matter what the wrapped callable's signature is.
Creating the
Adapter Class in C++ Core Requirements Recap
You want a class named Adapter that:
- Takes any callable (function pointer, functor, lambda) in its constructor
- Stores the callable by value (using
std::functionworks perfectly here) - Acts as a functor itself, wrapping the internal callable
- Enforces a fixed return type (
ReturnType) regardless of the wrapped callable's return type or parameter list
Implementation
First, let's write the code. This implementation uses C++20 features for simplicity (we'll cover compatibility notes later):
#include <functional> #include <utility> #include <type_traits> // Predefine your ReturnType, or make it a template parameter for flexibility using ReturnType = int; template <typename Ret = ReturnType> class Adapter { public: // Constructor: Accept any callable and wrap it to enforce Ret return type template <typename Callable> Adapter(Callable&& callable, Ret default_void_ret = {}) : m_wrapped_func([callable = std::forward<Callable>(callable), default_void_ret](auto&&... args) -> Ret { // Handle void return types from the wrapped callable if constexpr (std::is_void_v<std::invoke_result_t<decltype(callable), decltype(args)...>>) { std::invoke(callable, std::forward<decltype(args)>(args)...); return default_void_ret; } else { // Convert the callable's return value to Ret return static_cast<Ret>(std::invoke(callable, std::forward<decltype(args)>(args)...)); } }) {} // Make Adapter act as a functor: forward args to wrapped callable, return Ret template <typename... Args> Ret operator()(Args&&... args) const { return m_wrapped_func(std::forward<Args>(args)...); } private: // Generic std::function to accept any parameter list (C++20+) std::function<Ret(auto&&...)> m_wrapped_func; };
How It Works
Let's break down the key parts:
- Constructor: The template constructor accepts any callable. We wrap it in a lambda that handles two cases:
- If the wrapped callable returns
void, we execute it and return a default value forRet(you can customize this default via the constructor's second parameter). - For non-void return types, we cast the result to
Ret(adjust this cast if you need more complex conversion logic).
- If the wrapped callable returns
operator(): The templated operator accepts any number/type of arguments, forwards them to the wrapped function, and returns the enforcedRettype.std::function<Ret(auto&&...)>: This C++20 feature lets us store a callable that accepts any parameter list, which is perfect for handling the varied signatures of your input callables.
Example Usage
Let's test this with different callables to see it in action:
#include <iostream> #include <string> // Test 1: Regular function returning double double add(double a, double b) { return a + b; } // Test 2: Lambda returning void void print_greeting(const std::string& name) { std::cout << "Hello, " << name << "!\n"; } // Test 3: Functor returning bool struct PositiveChecker { bool operator()(int num) { return num > 0; } }; int main() { // Wrap the add function: converts double return to int Adapter<int> adapter_add(add); std::cout << adapter_add(2.7, 3.3) << "\n"; // Output: 6 // Wrap the print_greeting lambda: returns default int (0) after execution Adapter<int> adapter_greet([](const std::string& n) { print_greeting(n); }); std::cout << adapter_greet("Kirill") << "\n"; // Output: Hello, Kirill! followed by 0 // Wrap the functor: converts bool to int (true -> 1, false -> 0) Adapter<int> adapter_check(PositiveChecker{}); std::cout << adapter_check(-42) << "\n"; // Output: 0 // Wrap a no-argument function Adapter<int> adapter_fixed([]() { return 100; }); std::cout << adapter_fixed() << "\n"; // Output: 100 return 0; }
Compatibility Notes
- If you're stuck on C++17 (no support for
std::functionwith auto parameters), you can replace thestd::functionstorage with a templated member, but that makes theAdaptertype dependent on the wrapped callable's type. Alternatively, use type erasure manually, but it's more verbose. - If your
ReturnTypedoesn't have a default constructor, make sure to pass a valid default value to theAdapterconstructor for void-returning callables. - Adjust the
static_castto a custom conversion function if you need more control over how the wrapped callable's return value is converted toReturnType.
内容的提问来源于stack exchange,提问作者Kirill Frolov
相关产品推荐
相关产品推荐

