现在,我们有std::array,std::vector和括号的初始化,是C风格数组仍然需要?
这是source.cpp
#include <iostream>
struct A {
A(int i) : i(i) { std::cout << this << ": A(int)" << std::endl; }
A(A const &a) : i(a.i) { std::cout << this << ": A(A const &)" << std::endl; }
A(A &&a) : i(a.i) { std::cout << this << ": A(A &&)" << std::endl; }
~A() { std::cout << this << ": ~A()" << std::endl; }
private:
int i;
};
int main() {
std::cout << "#1 :" << std::endl;
A a1 = 1; …Run Code Online (Sandbox Code Playgroud) C++允许实例化一个类,通过初始化列表设置公共成员的值,如下例所示b1:
class B {
public:
int i;
std::string str;
};
B b1{ 42,"foo" };
B b2();
Run Code Online (Sandbox Code Playgroud)
; 但是,如果我提供构造函数
B(int k) { }
Run Code Online (Sandbox Code Playgroud)
,它不会编译.
那么,引擎盖后面发生了什么?是不是当没有提供构造函数时,编译器会提供一个?但它怎么能提供一个初始化列表?我认为它只会提供一个不带输入的"空白"构造函数,如示例所示b2.或者它同时提供?
c++ constructor initialization language-lawyer list-initialization
当我没有初始化所有项目时,我有一个关于初始化列表的问题。
假设我有以下代码:
class Example {
int a, b, c;
Example() : a(1), b(2), c(3) {}
}
Run Code Online (Sandbox Code Playgroud)
我知道成员初始化的顺序是由它们的声明顺序定义的,而不是由它们在初始化列表中列出的顺序定义的,但是,如果我在初始化列表中没有b,就像在下列的?
class Example {
int a, b, c;
Example() : a(1), c(2) {}
}
Run Code Online (Sandbox Code Playgroud)
a会被初始化为1,b会被初始化为未定义的值,c会被初始化为3吗?因为我没有严格按照我声明的顺序调用初始化列表,所以我会得到未定义的行为吗?或者这些都没有?
我问这个问题是因为我有一个包含大量数据的类,我想确保其中一些数据具有初始值,但我不需要初始化所有数据。
考虑以下代码:
#include <initializer_list>
class C {
public:
C() = delete;
C(int) {}
};
class D {
public:
D(std::initializer_list<C> il) {}
};
int main()
{
std::initializer_list<C> il{}; // fine: empty list, no need to construct C
D d2(il); // fine: calls initializer_list ctor with empty list
D d3{il}; // ditto
D d4({}); // still fine
D d5{{}}; // error: use of deleted function 'C::C()'
// WHY is the constructor of 'C' required here?
}
Run Code Online (Sandbox Code Playgroud)
我想D d5{{}};会用一个空列表调用initializer_list构造函数D …
我想编写一个可以与参数一起使用的函数,否则该函数可能直接出现在基于范围的循环中:
template <typename Iterable>
void sayIt(const Iterable& stuff) {
for (const auto& e : stuff) {
cout << e << endl;
}
}
Run Code Online (Sandbox Code Playgroud)
这适用于 stl 容器和其他类型,但不适用于大括号封闭的初始化程序:
std::vector<std::string> baz(2, "sorry");
sayIt(baz); // okay
sayIt({"foo", "bar"}); // not okay
Run Code Online (Sandbox Code Playgroud)
有没有办法让函数同时使用两者?
初始化二维数组时,我们可以这样做
int data[2][2] = {{1, 2}, {3, 4}}; // OK
Run Code Online (Sandbox Code Playgroud)
我们也可以使用
int data[2][2] = {1, 2, 3, 4}; // OK
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为 2D 数组仍然是一个连续的内存块。
当使用数组类而不是基类型时,这有效
array<array<int, 2>, 2> data = {1, 2, 3, 4}; // OK
Run Code Online (Sandbox Code Playgroud)
这又是有道理的,因为数组类没有任何额外的数据,并且最终也成为了一块连续的内存。
但是二维列表不起作用:
array<array<int, 2>, 2> data = {{1, 2}, {3, 4}}; // Error
Run Code Online (Sandbox Code Playgroud)
我也可以初始化这个
vector<array<int, 2>> data = {{1, 2}, {3, 4}}; // OK
Run Code Online (Sandbox Code Playgroud)
但无论如何都找不到初始化:
array<vector<int>, 2> = ????
Run Code Online (Sandbox Code Playgroud)
我的问题是:
是否有一个基本的设计原因(我的猜测与编译时与运行时发生的事情有关)?或者这只是我正在使用的编译器(GCC)的实现决定?
我正在寻找一种仅使用本机 C++ 语言功能(最高可达 C++17)的解决方案来完成以下任务:
std::array<Type, unsigned int Elem> array_{Type(), // 1 - Call constructor on Type()
Type(), // 2 - ...
... , // 3 - ...
Type()} // Elems - Call the Elem:th Type() constructor
Run Code Online (Sandbox Code Playgroud)
此外,我还希望每个构造函数调用都应该能够接受任意数量的参数。
一个具体的例子是自动编写以下内容:
std::array<std::shared_ptr<int>, 4> array_{std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>()}
Run Code Online (Sandbox Code Playgroud)
即,假设我知道 Type 和 Elem,我想自动化创建大括号括起来的初始值设定项列表的过程,并在该过程中调用 Type:s 构造函数。
有任何想法吗?
更新,我想解决的真正问题如下:
template <typename Type, unsigned int Size>
class Storage {
public:
Storage(std::initializer_list<Type> initializer) : array_{initializer} {}
private:
std::array<Type, Size> array_;
};
void foo(){
Storage<std::shared_ptr<int>, 100> storage(...);
// …Run Code Online (Sandbox Code Playgroud) 我有一个类有点像:
class Object {
public:
struct Flag {
const uint32_t bit = 0;
const wchar_t* name = L"";
const wchar_t sign = L"";
}
static std::map<const char*, Flag> Flags;
}
Run Code Online (Sandbox Code Playgroud)
我目前在VS2015,但想支持clang和gcc(最新的).我的问题是,我无法弄清楚如何用数据实际初始化该地图.
我尝试将其内联,例如:
static std::map<const char*, Flag> Flags = {
{ "FOO1", { 0, L"FOO1", L'A' } },
{ "FOO2", { 1, L"FOO3", L'B' } },
{ "FOO3", { 2, L"FOO3", L'C' } }
}
Run Code Online (Sandbox Code Playgroud)
但是抱怨说只有const整数类型可以在课堂上.好的!所以我只是将它作为类定义中的声明(如第一个代码片段所示),并将其放在关联的cpp中:
static std::map<const char*, Object::Flag> Object::Flags = {
{ "FOO1", { 0, L"FOO1", L'A' } }, …Run Code Online (Sandbox Code Playgroud) 我Matrix用这种类型的构造函数创建了一个类:
Matrix<T>(const vector<vector<T>> &m)
Run Code Online (Sandbox Code Playgroud)
如果我这样做,我可以实例化一个Matrix对象:
vector<vector<double>> a_v {
{ 17, 24, 1},
{ 23, 5, 7 },
{ 4, 6, 13 }
};
Matrix<double> a=a_v;
Run Code Online (Sandbox Code Playgroud)
它工作正常,但我认为che构造函数应该作为类型转换器,我认为这个代码也应该工作:
Matrix<double> a= {
{ 17, 24, 1},
{ 23, 5, 7 },
{ 4, 6, 13 }
};
Run Code Online (Sandbox Code Playgroud)
但是使用第二个代码我收到此错误:
无法将"{{17,24,1},{23,5,7},{4,6,13}}"从"大括号括号初始化列表"转换为"矩阵"
为什么C++11不转换brace-enclosed initializer到vector<vector<double>>自动?
如果我想以这种方式初始化矩阵,我该怎么办?