在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
考虑一下代码:
struct Foo
{
const char str[] = "test";
};
int main()
{
Foo foo;
}
Run Code Online (Sandbox Code Playgroud)
它无法使用g ++和clang ++编译,基本上吐出来
error: array bound cannot be deduced from an in-class initializer
我明白这是标准可能会说的,但有什么特别好的理由吗?由于我们有一个字符串文字,似乎编译器应该能够毫无问题地推断出大小,类似于简单地声明一个类外const的类似C的空终止字符串的情况.
struct bitfield {
int i = 0; // ok
int j : 8 = 0; // error: lvalue required as left operand of assignment
};
Run Code Online (Sandbox Code Playgroud)
使用C++ 11"类内初始化"功能初始化位字段的正确语法是什么?
我在我的项目中遇到以下错误:
error: use of deleted function ‘C::C(int)’ note: ‘C::C(int)’ is implicitly deleted because the default definition would be ill-formed: error: use of deleted function ‘M::M()’
这是我正在使用的代码:
struct M {
M(int){}
M() = delete; // Allowing this would work.
};
struct B {
B(int) {}
B() = delete;
};
struct C : public B {
using B::B;
M n = {5};
// C(int i) : B(i) {} // Adding this would work
};
C c{1};
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么会这样?
很明显,语言愿意在继承的构造函数的末尾添加更多的初始化(因为它愿意调用默认的构造函数).显然,它愿意隐式地将对非默认构造函数(类初始化)的调用添加到显式定义的构造函数的末尾.但由于某种原因,我不明白,它不愿意同时做这两件事.
根据这个问题,完美转发不够完美,不应该在这里使用.
注意:在实际情况下,构造函数 …
该锵文档整齐地解释说,
如果类或结构没有用户定义的默认构造函数,C++不允许您默认构造它的const实例([dcl.init],p9)
基本原理是如果const对象未正确初始化,则以后不能更改.以下代码仅具有用户声明的默认构造函数Test,但其所有成员都具有类内初始值设定项,
#include<iostream>
class Test
{
public:
Test() = default;
void print() const { std::cout << i << "\n"; }
private:
int i = 42; // will propagate to the default constructor!
};
int main()
{
Test const t; // <-- Clang chokes on the const keyword, g++ does not
t.print(); // prints 42
}
Run Code Online (Sandbox Code Playgroud)
所以用户提供默认构造函数的基本原理对我来说似乎是多余的.事实上,g ++ 4.8.1确实可以毫无问题地编译它(在线示例),尽管Clang <= 3.2没有.
问题:为什么完整的类内initalizers +用户声明的默认构造函数的组合不足以默认构造一个const对象?是否有针对C++ 14标准的修复程序?
更新:任何人都可以尝试使用Clang 3.3/3.4,看看与Clang …
在类初始化功能中,它允许在类本身内初始化普通成员,
struct A {
int a = 0; // error: ISO C++ forbids in-class initialization of non-const static member ‘a’
};
Run Code Online (Sandbox Code Playgroud)
这在最新的编译器gcc-4.6(with -std=c++0x)中给出了错误.将此功能制作成C++ 11标准还是gcc仍然不支持它?
我们认为可能会发生初始化异常.所以我们编写try/catch块.
int f(){
throw 1;
}
class A
{
public:
A() try : _k(f())
{}
catch (int)
{
std::cout << "Exception 1" << std::endl;
}
private:
int _k;
};
Run Code Online (Sandbox Code Playgroud)
但是这个问题在一个层面上重新排除了异常.这意味着下一个代码
try
{
A a;
} catch(int)
{
std::cout << "Exception 2" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
将输出:
Exception 1
Exception 2
Run Code Online (Sandbox Code Playgroud)
为什么这个try/catch块的行为与普通的try/catch块不同?
完整代码示例:http://ideone.com/XjY2d
c++ exception-handling exception try-catch in-class-initialization
Stack Overflow上有几个问题,分别是"为什么我不能在C++中初始化静态数据成员".大多数的答案与标准告诉你报什么你可以做; 那些试图回答为什么通常指向一个链接(现在似乎不可用)[编辑:实际上它可用,见下文]在Stroustrup的网站上,他声明允许静态成员的类内初始化会违反一个定义规则(ODR) ).
然而,这些答案似乎过于简单化.编译器完全能够在需要时解决ODR问题.例如,请考虑C++标头中的以下内容:
struct SimpleExample
{
static const std::string str;
};
// This must appear in exactly one TU, not a header, or else violate the ODR
// const std::string SimpleExample::str = "String 1";
template <int I>
struct TemplateExample
{
static const std::string str;
};
// But this is fine in a header
template <int I>
const std::string TemplateExample<I>::str = "String 2";
Run Code Online (Sandbox Code Playgroud)
如果我TemplateExample<0>在多个翻译单元中实例化,编译器/链接器魔法就会启动并且我TemplateExample<0>::str在最终可执行文件中只获得一个副本.
所以我的问题是,鉴于编译器显然可以解决模板类的静态成员的ODR问题,为什么它也不能为非模板类执行此操作呢?
编辑:Stroustrup FAQ响应可在此处获得.相关的句子是:
但是,为避免复杂的链接器规则,C++要求每个对象都有唯一的定义.如果C++允许将需要作为对象存储在内存中的实体的类内定义,则该规则将被破坏 …
c++ static-members one-definition-rule language-lawyer in-class-initialization
最小代码示例:
struct B {
union U {
struct S {} s;
int i = 100;
}
u;
};
Run Code Online (Sandbox Code Playgroud)
现在,如果我们声明一个B obj;,obj.u.i则分配一个垃圾值而不是100.请在此处查看演示.(垃圾值根据优化标志等而不同).
"类初始化"功能是否适用于联合.
int i = 100;?我有以下工作代码:
#include <string>
#include <iostream>
class A {
public:
const std::string test = "42";
//static const std::string test = "42"; // fails
};
int main(void){
A a;
std::cout << a.test << '\n';
}
Run Code Online (Sandbox Code Playgroud)
是否有充分理由不能进行测试static const?我确实在c ++ 11之前理解它受到标准的限制.我认为c ++ 11引入了类内初始化,使其更友好一些.很长一段时间以来,我也没有这种语义可用于整数类型.
当然它适用于以类的形式进行的类外初始化 const std::string A::test = "42";
我想,如果你能把它变成非静态的,那么问题在于其中一个.初始化它的类外范围(通常const是在对象实例化期间创建的).但是,如果您创建一个独立于该类的任何其他成员的对象,我认为这不是问题.第二个是静态成员的多个定义.例如,如果它包含在几个中.cpp文件,登陆到几个目标文件,然后链接器将这些对象链接在一起(例如,一个可执行文件)会有麻烦,因为它们将包含相同符号的副本.据我所知,这完全等同于在标题中的类声明下提供类外权利的情况,然后在多个地方包含这个公共标题.我记得,这会导致链接器错误.
但是,现在处理此问题的责任转移到用户/程序员.如果想要拥有一个static需要提供类外定义的库,则将其编译为单独的目标文件,然后将所有其他对象链接到此文件,因此只有一个二进制定义的副本符号.
我阅读了答案中我们是否还需要单独定义静态成员,即使它们是在类定义中初始化的?而我为什么不能初始化非const静态成员或类的静态数组?.
我还是想知道:
constexpr与用户定义的文字机制一起使用.clang和g ++都说变量不能有非文字类型.也许我可以做一个.(也许出于某种原因,这也是一个坏主意)static const应该是二进制精确的不可变副本.如果我遗失或错误理解某事,也请评论.