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

显式指定类型时std::make_tuple与tuple构造函数的行为差异

为什么显式指定类型调用std::make_tuple报错,但tuple构造函数正常?

先看代码示例:

const auto integer = 0;
const auto text = std::string{};

// 隐式推导类型的std::make_tuple构造tuple实例
const auto tuple_instance_with_implicit_make = std::make_tuple(integer, text);   // 正常
    
// 显式指定类型的std::make_tuple构造tuple实例
const auto tuple_instance_with_explicit_make = std::make_tuple<int, std::string>(integer, text); // 报错
    
// 显式指定类型的tuple构造函数构造实例
const auto tuple_instance_explicit = std::tuple<int, std::string>(integer, text); // 正常

// 隐式推导类型的tuple构造函数构造实例
const auto tuple_instance_implicit = std::tuple(integer, text);                   // 正常

运行时的错误信息:

error: cannot bind rvalue reference of type 'int&&' to lvalue of type 'const int'
   12 |     const auto tuple_instance_with_explicit_make = std::make_tuple<int, std::string>(integer, text); // ERROR
      |                                                                                      ^~~~~~~
In file included from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/uses_allocator_args.h:38,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/memory_resource.h:41,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/string:58,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/locale_classes.h:40,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/bits/ios_base.h:41,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/ios:44,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/ostream:40,
                 from /opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/iostream:41,
                 from <source>:1:
/opt/compiler-explorer/gcc-13.2.0/include/c++/13.2.0/tuple:1987:27: note:   initializing argument 1 of 'constexpr std::tuple<typename std::__strip_reference_wrapper<typename std::decay<_Elements>::type>::__type ...> std::make_tuple(_Elements&& ...) [with _Elements = {int, __cxx11::basic_string<char, char_traits<char>, allocator<char> >}]'
 1987 |     make_tuple(_Elements&&... __args)
      |                ~~~~~~~~~~~^~~~~~~~~~

核心原因:转发引用的生效条件不同

1. 显式指定模板参数时,std::make_tuple的参数不再是转发引用

std::make_tuple的签名简化后是:

template <class... Types>
tuple<...> make_tuple(Types&&... args);

转发引用的前提是模板参数Types由编译器自动推导。当你显式指定Types为int, std::string时,Types&&就变成了int&&和std::string&&——这是右值引用,而非转发引用。

右值引用只能绑定到非const的右值,而你传入的integer是const int左值,text是const std::string左值,无法匹配非const的右值引用,因此编译报错。

2. 显式指定tuple模板参数时,构造函数仍使用转发引用

std::tuple用于转发参数的构造函数签名是:

template <class... Args>
tuple(Args&&... args);

这里的Args是独立的模板参数,和tuple自身的模板参数(你显式指定的int, std::string)无关。无论是否显式指定tuple的模板参数,Args都会由编译器自动推导:

  • 传入const int左值时,Args推导为const int&,经过引用折叠后Args&&变为const int&,可以正常绑定左值;
  • 传入const std::string左值时同理。

因此显式指定tuple模板参数时,构造函数依然能正常接收参数。

补充:隐式调用的情况

  • 隐式调用std::make_tuple时,Types会被推导为const int&和const std::string&,引用折叠后参数类型为const int&和const std::string&,可以绑定左值;
  • 隐式调用tuple构造函数(C++17及以后支持)时,tuple的模板参数会根据传入参数推导,构造函数的Args也正常推导,因此运行正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:20:23