为什么`initializer_list<pair>`和`initializer_list<tuple>`表现不同?

15
以下代码编译并运行:
#include <initializer_list>
#include <iostream>
#include <vector>
#include <tuple>

void ext( std::initializer_list<std::pair<double, std::vector<double> >> myList )
{
    //Do something
}

///////////////////////////////////////////////////////////

int main(void) {
    ext( { {1.0, {2.0, 3.0, 4.0} } } );
    return 0;
}

虽然这个不做:

#include <initializer_list>
#include <iostream>
#include <vector>
#include <tuple>

void ext( std::initializer_list<std::tuple<double, std::vector<double> >> myList )
{
    //Do something
}

///////////////////////////////////////////////////////////

int main(void) {
    ext( { {1.0, {2.0, 3.0, 4.0} } } );
    return 0;
}

唯一的区别在于第一种情况下ext()函数需要一个类型为initializer_list<pair>的参数(可用)而另一个则使用了initializer_list<tuple>(不可用)。然而,cplusplus.com说明:

pair是tuple的一种特殊情况。

那么为什么一段代码可用而另一段不行呢?


额外信息

第二种情况下,clang++输出的错误是:

main.cpp:33:2: error: no matching function for call to 'ext'
      ext( { {1.0, {2.0, 3.0, 4.0} } } );
      ^~~
main.cpp:7:6: note: candidate function not viable: cannot convert initializer list argument to 'std::tuple<double,
      std::vector<double, std::allocator<double> > >'
void ext( std::initializer_list<std::tuple<double, std::vector<double> >> myList )
      ^
1 error generated.

当g++编译器输出如下信息:

main.cpp: In function ‘int main()’:
main.cpp:33:35: error: converting to ‘std::tuple<double, std::vector<double, std::allocator<double> > >’ from initializer list would use explicit constructor ‘constexpr std::tuple<_T1, _T2>::tuple(const _T1&, const _T2&) [with _T1 = double; _T2 = std::vector<double>]’
  ext( { {1.0, {2.0, 3.0, 4.0} } } );
                                   ^
1个回答

16

cplusplus.com网站不是一个很好的网站,因为它充满了错误的陈述,比如“对”Pairs“是”tuple“的一个特殊情况”。你可以使用cppreference代替。实际上,pair不是tuple的一个特例。

现在认为tuple是更好的设计;pair相当古老,由于向后兼容性无法更改。

错误消息表明,区别在于tuple具有explicit构造函数,而pair没有。

这意味着在构造元组时需要提及类名:

 ext( { std::tuple<double,std::vector<double>>{1.0, {2.0, 3.0, 4.0} } } );
这将在C++17中进行更改:仅当元组中的一个类型是具有显式构造函数的类类型时,tuple的构造函数才是显式的。gcc 6已经实现了此功能。(Credit - Jonathan Wakely)。请参见N4387

4
注意,现在 tuple 构造函数的显式(explicit)程度取决于参数类型,而且这个例子代码将在 C++17 中是有效的(并且现在可以使用 GCC 6 编译)。 - Jonathan Wakely
@JonathanWakely 谢谢你提供的信息。我只是在想,如果 OP 问“为什么要显式声明,这看起来很烦人”,我该如何回答,因为我没有好的答案。 - M.M
@M.M 感谢您的帮助!确实,那是一个好问题... - Gael Lorieul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接