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

使用auto和std::make_tuple遍历std::tuple时出现编译错误

问题描述

我学到了一种遍历std::tuple的实现,但调用traverse(_functions, _data_1)时出现编译错误,无法理解显式声明类型的std::tuple<char, int, float, std::string> _data_0和用std::make_tuple+auto的_data_1在约束条件上的差异。

代码实现

#include <concepts>
#include <iostream>
#include <tuple>
#include <type_traits>

template <std::size_t t_idx, typename... t_function, typename... t_data>
requires(... and std::is_invocable_r_v<
         void, t_function,
         t_data &>) void traverse_each(std::tuple<t_function...> p_function,
                                       std::tuple<t_data...> &p_data) {
  std::get<t_idx>(p_function)(std::get<t_idx>(p_data));
}

template <std::size_t... t_idxs, typename... t_function, typename... t_data>
requires(... and std::is_invocable_r_v<
         void, t_function,
         t_data &>) void traverse_all(std::index_sequence<t_idxs...>,
                                      std::tuple<t_function...> p_function,
                                      std::tuple<t_data...> &p_data) {
  (traverse_each<t_idxs>(p_function, p_data), ...);
}

template <typename... t_function, typename... t_data>
requires(... and std::is_invocable_r_v<
         void, t_function,
         t_data &>) void traverse(std::tuple<t_function...> p_function,
                                  std::tuple<t_data...> &p_data) {
  traverse_all(std::make_index_sequence<sizeof...(t_data)>{}, p_function,
               p_data);
}

int main() {
  auto _functions{std::make_tuple(
      [](char &p_char) { std::cout << "char: " << p_char << std::endl; },
      [](int &p_int) { std::cout << "int: " << p_int << std::endl; },
      [](float &p_float) { std::cout << "float: " << p_float << std::endl; },
      [](std::string &p_str) {
        std::cout << "string: " << p_str << std::endl;
      })};

  std::tuple<char, int, float, std::string> _data_0{'k', -19, 8.014, "bye"};
  traverse(_functions, _data_0);

  auto _data_1 =
      std::make_tuple('k', static_cast<int>(-19), 8.014, std::string("bye"));
  traverse(_functions, _data_1);
}

编译错误信息

main.cpp:46:3: No matching function for call to 'traverse'
main.cpp:26:26: candidate template ignored: constraints not satisfied [with t_function = <(lambda at /var/tmp/baires/main.cpp:34:7), (lambda at /var/tmp/baires/main.cpp:35:7), (lambda at /var/tmp/baires/main.cpp:36:7), (lambda at /var/tmp/baires/main.cpp:37:7)>, t_data = <char, int, double, std::basic_string<char>>]
main.cpp:24:18: because 'std::is_invocable_r_v<void, (lambda at /var/tmp/baires/main.cpp:36:7), double &>' evaluated to false

问题原因与解决办法

核心差异

std::make_tuple会根据传入的实参自动推导类型:你传入的8.014是浮点字面量,默认类型为double,因此_data_1的第三个元素类型是double;而显式声明的_data_0指定了第三个元素为float,编译器会自动把8.014隐式转换为float存入元组。

你的第三个lambda函数签名是[](float &p_float),仅能接受float&类型参数,但_data_1的第三个元素是double,无法绑定到float&,导致std::is_invocable_r_v检查失败,模板约束不满足,从而触发编译错误。

解决办法

你可以通过以下几种方式修复:

  1. 显式指定std::make_tuple的模板参数
    强制生成包含float的元组:

    auto _data_1 = std::make_tuple<char, int, float, std::string>('k', -19, 8.014, "bye");
    
  2. 将浮点字面量显式转换为float
    让make_tuple推导第三个元素为float:

    auto _data_1 = std::make_tuple('k', static_cast<int>(-19), static_cast<float>(8.014), std::string("bye"));
    
  3. 放宽lambda的参数类型限制
    用auto&让lambda接受任意浮点类型:

    [](auto &p_num) { std::cout << "float/double: " << p_num << std::endl; },
    
  4. 调整模板约束的检查逻辑
    若希望允许参数隐式转换,可将约束中的t_data &替换为std::add_lvalue_reference_t<std::decay_t<t_data>>,不过这种方式可能引入潜在问题,需谨慎使用。


内容的提问来源于Stack Exchange,提问作者canellas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:07:23