我真的不明白这一点,我认为编译器首先执行大括号中的内容然后将结果赋予最合适的函数.这看起来它给函数一个初始化列表来处理它...
#include <string>
#include <vector>
using namespace std;
void func(vector<string> v) { }
void func(vector<wstring> v) { }
int main() {
func({"apple", "banana"});
}
Run Code Online (Sandbox Code Playgroud)
错误:
<stdin>: In function 'int main()':
<stdin>:11:27: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
<stdin>:11:27: note: candidates are:
<stdin>:6:6: note: void func(std::vector<std::basic_string<char> >)
<stdin>:8:6: note: void func(std::vector<std::basic_string<wchar_t> >)
Run Code Online (Sandbox Code Playgroud)
为什么不func(vector<string> v)调用我的超载,我可以这样做吗?
我一直在研究如何initializer_list实现,所以我找到了标准的第18.9节,并找到了一个简单的界面.我认为制作我自己命名的版本MyNamespace::InitializerList和用例是有益的:
template<class T>
class ArrayPrinter
{
public:
ArrayPrinter(MyNamespace::InitializerList<T> list)
{
for (auto i : list) cout << i << endl;
}
};
...
ArrayPrinter ap{ {1,2,3} };
Run Code Online (Sandbox Code Playgroud)
我很惊讶地发现这不起作用,编译器抱怨它找不到合适的构造函数(它想给我3个参数但是第18.9节只描述了一个默认的构造函数).
经过一番摆弄后,我发现我的班级必须完全命名std::initializer_list才能奏效.我还可以别名std::initializer_list成MyNamespace,但我不能别名MyNamespace::InitializerList为std::initializer_list.
它似乎不是真正的语言功能,因为它取决于标准库?
我的问题的要点是为什么名称如此重要以及它试图传递给构造函数的那3个参数是什么?
考虑以下初始化:
/* C, C++ */
int a[] = { f(), g() };
struct { int x, y } foo = { f(), g() };
/* C++ */
struct goo { goo(int x, int y); };
goo b = { f(), g() };
goo c { f(), g() }; /* C++11 */
goo d ( f(), g() );
Run Code Online (Sandbox Code Playgroud)
是执行的顺序f()和g()在由C和C++标准中规定的任何行?
在C++ 11中,我们可以使用"brace-or-equal-initializer"(标准中的单词)进行类内初始化,如下所示:
struct Foo
{
/*explicit*/ Foo(int) {}
};
struct Bar
{
Foo foo = { 42 };
};
Run Code Online (Sandbox Code Playgroud)
但如果我们不发表评论explicit,它就不再编译了.GCC 4.7和4.9说:
error: converting to ‘Foo’ from initializer list would use explicit constructor ‘Foo::Foo(int)’
Run Code Online (Sandbox Code Playgroud)
我发现这令人惊讶.C++ 11标准真的是这个代码无法编译的意图吗?
删除它=修复它:Foo foo { 42 };但我个人觉得更难以向那些已经习惯了这种形式的人解释=几十年,而且由于标准指的是"支撑或平等初始化器",因此很好的旧方式在这种情况下不起作用.
c++ explicit-constructor initializer-list in-class-initialization c++11
我有以下构造函数:
MyItem(std::initializer_list<double> l) {
std::cout << "l size " << l.size() << ")" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
以后用双花括号调用:
MyItem{{}}
Run Code Online (Sandbox Code Playgroud)
结果l.size()给出的是1.
这种行为背后的机制是什么?
似乎嵌套的{}扮演的是唯一元素的默认构造函数,但我不太明白为什么以及类型推导在这里如何工作.
基于此代码
struct Foo
{
Foo()
{
cout << "default ctor" << endl;
}
Foo(std::initializer_list<Foo> ilist)
{
cout << "initializer list" << endl;
}
Foo(const Foo& copy)
{
cout << "copy ctor" << endl;
}
};
int main()
{
Foo a;
Foo b(a);
// This calls the copy constructor again!
//Shouldn't this call the initializer_list constructor?
Foo c{b};
_getch();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
默认ctor
复制ctor
复制ctor
在第三种情况下,我将b放入大括号初始化,它应该调用initializer_list <>构造函数.
相反,复制构造函数起带头作用.
你们有人会告诉我这是如何运作的,为什么?
std::initializer_list 由编译器从大括号括起的init列表构造,并且该列表的大小必须是编译时常量.
那么为什么委员会决定从模板参数中省略大小呢?这可能会阻止一些优化并使一些事情变得不可能(std::array从a 初始化std::initializer_list).
std :: shared_ptr构造函数的行为不符合我的预期:
#include <iostream>
#include <vector>
void func(std::vector<std::string> strings)
{
for (auto const& string : strings)
{
std::cout << string << '\n';
}
}
struct Func
{
Func(std::vector<std::string> strings)
{
for (auto& string : strings)
{
std::cout << string << '\n';
}
}
};
int main(int argc, const char * argv[])
{
func({"foo", "bar", "baz"});
Func({"foo", "bar", "baz"});
//auto ptr = std::make_shared<Func>({"foo", "bar", "baz"}); // won't compile.
//auto ptr = std::make_shared<Func>{"foo", "bar", "baz"}; // nor this.
return 0;
} …Run Code Online (Sandbox Code Playgroud) std::initializer_list我所看到的大多数C++ 11代码都是按值来获取的,但有时它是由右值引用获取的.这样做有什么好的理由吗?
例如,我遇到的几乎所有例子都是这样的:
class A {
public:
A(std::initializer_list<int>);
};
Run Code Online (Sandbox Code Playgroud)
但我偶尔会看到这件事:
class B {
public:
B(std::initializer_list<int> &&);
};
Run Code Online (Sandbox Code Playgroud)
我理解一般的rvalue引用的用途和目的,但为什么在a的情况下,其中一个优先于另一个std::initializer_list?我唯一能想到的是class A允许初始化列表单独构建,并class B防止这种情况发生.
std::initializer_list<int> values {1,2,3,4};
A a(values); // valid
B b(values); // error
Run Code Online (Sandbox Code Playgroud)
但我想不出一个很好的理由,为什么要防止这是一件令人满意的事情.
那么,为什么会std::initializer_list采用右值参考而不是值?
当我发现下面的代码输出"指针"时,我遇到了真实的WTF时刻.
#include <iostream>
#include <utility>
template<typename T>
struct bla
{
static void f(const T*) { std::cout << "pointer\n"; }
static void f(const T&) { std::cout << "reference\n"; }
};
int main()
{
bla<std::pair<int,int>>::f({});
}
Run Code Online (Sandbox Code Playgroud)
将std::pair<int,int>模板参数更改为int或任何其他基本类型,给(至少对我来说)预期的"模糊过载"错误.似乎内置类型在这里是特殊的,因为任何用户定义的类型(聚合,非平凡,具有默认构造函数等)都会导致调用指针超载.我相信模板不是重现它的必要条件,它只是让尝试不同类型变得简单.
就个人而言,我不认为这是合乎逻辑的,我认为在所有情况下都会出现模糊的重载错误,无论模板参数如何.GCC和Clang(我相信MSVC)在C++ 11/14/1z中都不同意我的观点.注意我完全知道这两个重载存在的错误API ,我保证不会写这样的东西.
所以问题就变成了:发生了什么?