为啥带有两个元素的初始化器语法将一个元素放入字符串向量而不是两个?

Posted

技术标签:

【中文标题】为啥带有两个元素的初始化器语法将一个元素放入字符串向量而不是两个?【英文标题】:Why does initalizer syntax with two elements put one element to a vector of strings instead of two?为什么带有两个元素的初始化器语法将一个元素放入字符串向量而不是两个? 【发布时间】:2019-10-08 13:59:23 【问题描述】:

为什么我在b 中得到一个元素而不是两个?在a 中,我按预期得到一个,在c 中按预期得到三个元素。具有两个值的那个在某种程度上是一种特殊情况。

#include <string>
#include <vector>
#include <iostream>

void print(const std::string& name, const std::vector<std::string>& v)

    std::cout << name << ' ' << v.size() << '\n';
    for (const auto& str : v) 
        std::cout << str << '\n';
    
    std::cout << "\n";


int main()

    std::vector<std::string> a = "str1";
    std::vector<std::string> b = "str1", "str2";
    std::vector<std::string> c = "str1", "str2", "str3";
    print("a", a);
    print("b", b);
    print("c", c);
    return 0;

打印出来:

a 1
str1

b 1
str1

c 3
str1
str2
str3

我猜这与向量 ctor 的重载有关。

template< class InputIt >
vector( InputIt first, InputIt last,
    const Allocator& alloc = Allocator() );

我使用 clang 9.0.0 和 -std=c++17 -O2 -Wall 作为标志。

b 的情况下编译器做了什么?为什么它决定它在一种情况下是迭代器而在其他情况下是初始化列表?我的示例代码定义明确还是有 UB?

【问题讨论】:

类似于Why does the number of elements in a initializer list cause an ambiguous call error?。 ... 替换... 可以解决问题。 【参考方案1】:

我的示例代码定义明确还是有 UB?

它确实有 UB。采用first-last 迭代器对的构造函数假定两个迭代器引用相同的序列。 "str1", "str2" 不满足这个要求,因此是 UB。

b 的情况下编译器做了什么?为什么它决定它在一种情况下是迭代器而在其他情况下是初始化列表?

回想一下,字符串文字“str1”的类型为char const[5]。但是,对 std::initializer_list 的构造函数重载的调用适用于 std::string 实例。这需要隐式转换 - 由于两个迭代器的构造函数模板不需要这样的转换,因此它被认为是更好的匹配。


您可以通过使用一对大括号强制直接列表初始化来解决此问题,

std::vector<std::string> b2 = "str1", "str2";

或通过手动指定所需的类型至少一次:

std::vector<std::string> b3 = std::string("str1"), "str2";

using namespace std::string_literals;
std::vector<std::string> b4 = "str1"s, "str2"s;

【讨论】:

以上是关于为啥带有两个元素的初始化器语法将一个元素放入字符串向量而不是两个?的主要内容,如果未能解决你的问题,请参考以下文章

jquery even选择器 语法

jquery odd选择器 语法

js指定分隔符连接数组元素join()

fortran程序如何将两个数组中的元素,放入一个数组?

python之pyquery库

JavaScript join() 方法