使用 std::make_tuple 实例化具有显式指定类型的元组与使用元组构造函数 [duplicate] 之间的区别

Difference between instantiating a tuple with explicitly specified types using std::make_tuple and using the tuple constructor [duplicate]

提问人:user21796467 提问时间:11/1/2023 最后编辑:user21796467 更新时间:11/1/2023 访问量:67

问:

这个问题在这里已经有答案了:
23天前关闭。

这篇文章是在 23 天前编辑并提交审核的。

以下面的代码片段为例,该代码片段使用 std::make_tuple 函数和元组构造函数实例化一些元组实例:

...

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

/* tuple instance constructed using std::make_tuple with implicit type deduction */
const auto tuple_instance_with_implicit_make = std::make_tuple(integer, text);   // OK
    
/* tuple instance constructed using std::make_tuple with explicitly specified types */
const auto tuple_instance_with_explicit_make = std::make_tuple<int, std::string>(integer, text); // ERROR
    
/* tuple instance using tuple constructor with explicitly specified types */
const auto tuple_instance_explicit = std::tuple<int, std::string>(integer, text); // OK

/* tuple instance using tuple constructor with implicit type deduction */
const auto tuple_instance_implicit = std::tuple(integer, text);                   // OK
    
...

当我运行代码时,对于使用具有显式指定类型的 std::make_tuple 函数的情况,我收到以下错误,但对于直接将元组构造函数与显式指定类型一起使用的情况,则不会出现以下错误:

 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)
      |                ~~~~~~~~~~~^~~~~~~~~~

由于 std::make_tuple 函数和元组构造函数都对其参数使用转发引用,并且 std::make_tuple 将传递的参数转发给元组构造函数,因此我本来希望具有相同的行为。据我所知,转发引用可以绑定到任何值类别的对象和表达式,无论是值还是右值

有人可以帮我理解这种行为吗?为什么使用具有显式指定类型的构造函数创建元组实例有效,但以相同方式使用 std::make_tuple 的元组实例却不行?

C++ 完美转发 stdtuple 正向引用

评论

0赞 273K 11/1/2023
请参阅第二个骗局,它解释了为什么 int 和 std::string 模板参数无效并且会起作用。std::make_tuple<const int&, const std::string&>(integer, text)
0赞 Pepijn Kramer 11/1/2023
旁注:但 std::tuple 是(元)模板编程的构建块。在几乎所有其他情况下,您最好创建自己的结构(具有可读的成员名称)。在你的情况下,就像struct my_struct { int value; std::string name;};
0赞 alfC 11/1/2023
经验法则:切勿指定模板函数的推导模板参数。

答: 暂无答案