C++ - 使用std::string进行统一初始化

13

我正在尝试使用C++中的字符串类来使用统一的初始化器。以下是代码:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string str1 {"aaaaa"};
    string str2 {5, 'a'};
    string str3 (5, 'a');

    cout << "str1: " << str1 << endl;
    cout << "str2: " << str2 << endl;
    cout << "str3: " << str3 << endl;

    return 0;
}

输出结果将是:

str1: aaaaa
str2: a
str3: aaaaa
这让我感到困惑。为什么str2无法像str3一样达到预期的结果?

2
"Uniform"初始化... - Kerrek SB
2个回答

10

您正在使用带有以下签名的std::string构造函数

std::basic_string( std::initializer_list<CharT> init, const Allocator& alloc = Allocator() );

编译器将5视为char类型,这转换成了一个在屏幕上不会显示的ASCII类型。如果您将该5更改为可打印的值,比如ASCII值为65A

string str2 {65, 'a'};

它将打印:

Aa

点击此处即可在Coliru上查看,并附带更多插图。


10

std::string提供了一个接受initializer_list参数的构造函数。

basic_string( std::initializer_list<CharT> init,
              const Allocator& alloc = Allocator() );

当您使用花括号初始化列表构造std::string时,该构造函数始终优先考虑。仅当花括号初始化列表中的元素无法转换为initializer_list中元素的类型时,才考虑其他构造函数。这在[over.match.list]/1中有提到。

最初,候选函数是类T的初始化器列表构造函数([dcl.init.list]),参数列表由初始化器列表作为单个参数组成。

在您的示例中,第一个参数5可以隐式转换为char,因此initializer_list构造函数是可行的,并且被选择。
如果您将字符串中的每个字符打印为int,这一点就很明显了。
void print(char const *prefix, string& s)
{
    cout << prefix << s << ", size " << s.size() << ": ";
    for(int c : s) cout << c << ' ';
    cout << '\n';
}

string str1 {"aaaaa"};
string str2 {5, 'a'};
string str3 (5, 'a');

print("str1: ", str1);
print("str2: ", str2);
print("str3: ", str3);

输出:

str1: aaaaa, size 5: 97 97 97 97 97 
str2: a, size 2: 5 97 
str3: aaaaa, size 5: 97 97 97 97 97 

现场演示


谢谢。有点明白这里发生了什么。我一直更喜欢统一初始化,因为我被告知这是现在的最佳实践(我对C++还是新手)。看来我从现在开始要小心了。 - Hafiz Hilman Mohammad Sofian
1
@Hilman,正如你所发现的那样,它并不总是如此“一致”。例如,在使用vector<int>时,vector<int> v1{4,2}, v2(4,2);。在这里,v1包含两个整数4和2,而v2包含4个整数,每个都初始化为2。 - Praetorian

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