如何让function_creater接受任意容器并构造std::enable_if约束
function_creater for Any Container with SFINAE Got it, let's tackle this problem step by step. You want to generalize your function_creater to work with any container instead of just std::list, and you already have an is_container type trait—great start. The missing piece is how to use SFINAE to validate that the return type of the input std::function is a container holding the correct std::function<void(T&)> elements.
Step 1: Add a Trait to Extract std::function Details
First, we need a way to pull out the return type and input argument type from the input std::function. A simple template trait will handle this:
#include <functional> #include <type_traits> #include <list> // Your existing is_container trait template <typename T, typename = void> struct is_container : std::false_type {}; template <typename T> struct is_container< T, std::void_t<decltype(std::begin(std::declval<T&>()))> > : std::true_type {}; template <typename C> constexpr auto is_container_v = is_container<C>::value; // New trait to extract std::function's return and argument types template <typename F> struct function_traits; template <typename Ret, typename Arg> struct function_traits<std::function<Ret(Arg)>> { using return_type = Ret; using argument_type = Arg; }; template <typename F> using function_return_t = typename function_traits<F>::return_type; template <typename F> using function_argument_t = typename function_traits<F>::argument_type;
Step 2: Implement the Generalized function_creater
Now we can use these traits in std::enable_if to enforce two key conditions:
- The return type of the input
std::functionis a container (using youris_container_v). - The container's elements are exactly
std::function<void(T&)>(whereTis the input argument type of the inputstd::function).
Here's the implementation:
template <typename Func> auto function_creater(Func trans_func) -> std::enable_if_t< // Check if the return type of trans_func is a container is_container_v<function_return_t<Func>> && // Check if the container holds the correct function type std::is_same_v< typename function_return_t<Func>::value_type, std::function<void(std::remove_reference_t<function_argument_t<Func>>&)> >, // Return type matches your original signature std::function<std::list<std::remove_reference_t<function_argument_t<Func>>>(std::remove_reference_t<function_argument_t<Func>>&)> > { using T = std::remove_reference_t<function_argument_t<Func>>; using Container = function_return_t<Func>; // Your core implementation logic here (adjust as needed) return [trans_func](T& input) -> std::list<T> { std::list<T> result; auto funcs = trans_func(input); for (auto& func : funcs) { T elem = input; // Assume T is copyable; adjust for move semantics if needed func(elem); result.push_back(std::move(elem)); } return result; }; }
Step 3: Test with a Custom Container Example
Let's verify this works with std::vector instead of std::list:
#include <vector> // Example trans_func returning a vector of functions template <typename T> std::vector<std::function<void(T&)>> sample_trans_func(T& input) { return { [](T& x) { x += 1; }, [](T& x) { x *= 2; } }; } int main() { // The compiler will auto-deduce T=int and Container=std::vector auto processor = function_creater(std::function<std::vector<std::function<void(int&)>>>(sample_trans_func<int>)); int val = 5; auto result = processor(val); // Result will be a std::list<int> containing 6 and 10 return 0; }
Key Notes
- If you want to restrict
function_createrto only acceptstd::functioninstances (not raw function pointers/lambdas directly), you can adjust the template parameter to explicitly takestd::function<Container(T&)>instead of a genericFunc. - Your
is_containertrait works for all standard containers (since they all havebegin()), but you can extend it if you need to support custom containers with different iteration APIs.
内容的提问来源于stack exchange,提问作者Jakobo06

