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

将std::tuple、make_tuple、apply适配至etl库的技术咨询

ETL库适配std::tuple/std::apply的C++模板代码问题

问题梳理

  • 误将etl::variant当作std::tuple的替代方案:ETL中找不到对应std::make_tuple的接口,错误选用etl::variant存储多参数,且初始化方式存疑。
  • 索引序列实现apply功能报错:将std::tuple替换为etl::variant后,自定义的apply逻辑无法编译通过。

原代码(标准库版本)

#include <functional>
#include <tuple>

template <typename Function, typename... Args>
class Class {
private:
    Function function_;
    std::tuple<Args...> args;

public:
    Class(Function _function, Args... _args)
        : function_{std::forward<Function>(_function)}
        , args{std::forward<Args>(_args)...} {}

    auto function() {
        return std::apply(function_, args);
    }
};

错误替换尝试代码

// 错误:用variant替代tuple
etl::variant<Args...> args;
public:
    Class(Function _function, Args... _args) :  
        function_ { etl::forward<Function>(_function) } ,
        args{/*std::make_tuple*/
            etl::forward<Args>(_args)...
        } // 疑问:是否需要make_tuple?
{}

报错的apply适配代码

template <typename... Args, int... Is>
void func(etl::variant < Args... > & tup, helper::index < Is... > ) {
  f(std::get < Is > (tup)...);
}

template < typename...Args, int...Is >
void func(etl::variant < Args... > & tup, helper::index < Is... > ) {
    f(std::get < Is > (tup)...);
}
template < typename...Args >
void func(etl::variant < Args... > & tup) {
    func(tup, helper::gen_seq < sizeof...(Args) > {}); // 此处报错
}

解决方案

核心错误纠正

etl::variant是单值变体类型(同一时刻仅能存储一个类型的值),和std::tuple(多值聚合类型,同时存储多个不同类型的值)语义完全不同,不能互相替换。ETL中对应std::tuple的类型是etl::tuple,提供与标准库tuple一致的接口(包括etl::get、etl::make_tuple等)。

修正后的完整代码

#include <etl/delegate.h>
#include <etl/tuple.h>
#include <etl/utility.h> // 提供etl::forward

template <typename Function, typename... Args>
class Class {
private:
    // 用etl::delegate替代原始Function类型,更符合ETL库的用法
    using FuncSignature = typename etl::function_traits<Function>::signature;
    etl::delegate<FuncSignature> function_;
    etl::tuple<Args...> args;

public:
    Class(Function _function, Args... _args)
        : function_(etl::forward<Function>(_function))
        , args(etl::forward<Args>(_args)...) {}

    auto function() {
        return apply(function_, args);
    }

private:
    // 辅助索引序列实现
    template <std::size_t... Is>
    struct index_sequence {};

    template <std::size_t N, std::size_t... Is>
    struct gen_index_sequence : gen_index_sequence<N-1, N-1, Is...> {};

    template <std::size_t... Is>
    struct gen_index_sequence<0, Is...> : index_sequence<Is...> {};

    // 适配etl::tuple的apply核心逻辑
    template <typename Func, typename... TupleArgs, std::size_t... Is>
    auto apply_impl(Func&& func, etl::tuple<TupleArgs...>& tup, index_sequence<Is...>) {
        return etl::forward<Func>(func)(etl::get<Is>(tup)...);
    }

    template <typename Func, typename... TupleArgs>
    auto apply(Func&& func, etl::tuple<TupleArgs...>& tup) {
        return apply_impl(etl::forward<Func>(func), tup, gen_index_sequence<sizeof...(TupleArgs)>{});
    }
};

关键说明

  1. 类型替换:用etl::tuple直接替换std::tuple,初始化方式与原代码一致,无需额外修改;若需要显式构造,可使用etl::make_tuple。
  2. 函数封装:用etl::delegate替代原始函数类型,通过etl::function_traits推导函数签名,更符合ETL库的使用习惯。
  3. apply实现:ETL部分版本未内置etl::apply,通过自定义索引序列展开etl::tuple的元素,传递给目标函数,逻辑与std::apply一致。
  4. 报错原因:原代码中用etl::variant替代tuple后,std::get<Is>(tup)语义错误——variant的get是获取当前激活的单值,而tuple的get是按索引取多值中的对应元素,二者无法兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:54:32