You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让function_creater接受任意容器并构造std::enable_if约束

Generalizing 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:

  1. The return type of the input std::function is a container (using your is_container_v).
  2. The container's elements are exactly std::function<void(T&)> (where T is the input argument type of the input std::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_creater to only accept std::function instances (not raw function pointers/lambdas directly), you can adjust the template parameter to explicitly take std::function<Container(T&)> instead of a generic Func.
  • Your is_container trait works for all standard containers (since they all have begin()), but you can extend it if you need to support custom containers with different iteration APIs.

内容的提问来源于stack exchange,提问作者Jakobo06

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:07:59