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

Gae*_*eul 14 c++ tuples initializer-list std-pair

以下代码编译并运行:

#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;
}
Run Code Online (Sandbox Code Playgroud)

虽然这个没有:

#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;
}
Run Code Online (Sandbox Code Playgroud)

唯一的区别是,在第一种情况下,ext()函数接受类型initializer_list<pair>(工作)的参数而另一个使用initializer_list<tuple>(不起作用).但是,cplusplus.com表示

对是元组的特例.

那么为什么一个代码工作而另一个代码不工作呢?


附加信息

第二种情况下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.
Run Code Online (Sandbox Code Playgroud)

而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} } } );
                                   ^
Run Code Online (Sandbox Code Playgroud)

M.M*_*M.M 15

cplusplus.com不是一个非常好的网站,因为它充满了虚假陈述,如"对是一个特殊的元组案例".你可以cppreference改用.事实上,对不是元组的特例.

现在考虑的tuple是更好的设计; pair由于向后兼容性,现在已经相当多了,现在无法更改.

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

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

 ext( { std::tuple<double,std::vector<double>>{1.0, {2.0, 3.0, 4.0} } } );
Run Code Online (Sandbox Code Playgroud)

这将在C++ 17中进行更改:tuple当且仅当其中一个元组的类型是具有显式构造函数的类类型时,构造函数才是显式的.gcc 6已经实现了这个功能.(信用 - 乔纳森威克利).见N4387

  • 注意,元组构造函数的`explicit`-ness现在以参数类型为条件,示例代码在C++ 17中有效(今天用GCC 6编译). (4认同)