GCC 4.9.2不编译此代码段,但是clang 3.5.0可以编译.哪一个是正确的?
enum F : int { x, y, z};
int F;
enum F:int f = F::x;
Run Code Online (Sandbox Code Playgroud)
GCC输出:
main.cpp:3:12: error: expected ';' or '{' before 'f'
enum F:int f = F::x;
^
main.cpp:3:12: error: expected class-key before 'f'
main.cpp:3:14: error: invalid type in declaration before '=' token
enum F:int f = F::x;
^
main.cpp:3:16: error: 'F' is not a class, namespace, or enumeration
enum F:int f = F::x;
^
Run Code Online (Sandbox Code Playgroud)
我相信GCC是正确的,因为一个简单声明(包含精心设计的类型说明符enum F)不允许使用enum-base …
在尝试理解C++标准中的"构造函数没有名称"这一短语时,似乎我在clang中发现了一个错误.有人能证实吗?
VS2015和 gcc拒绝这段代码,而且我认为他们这是是正确的.至少,这是我从N4140的§12.1[class.ctor]/2得到的印象:
#include <iostream>
class A {
public:
A() { std::cout << "A()" << '\n'; }
};
int main()
{
A::A();
}
Run Code Online (Sandbox Code Playgroud)
N4140中的§12.1[class.ctor]/2:
构造函数用于初始化其类类型的对象.因为构造函数没有名称,所以在名称查找期间永远不会找到它们; ...
使用A::A();上面的表达式,clang通过名称查找找到构造函数,A而不是它应该找到类型名称.查看实例.
为什么B :: f不解决歧义,但A :: f呢?
namespace A
{
class X { };
void f( X );
}
namespace B
{
void f( A::X );
void g( A::X x )
{
using B::f; // which expression shall I use here to select B::f?
f(x); // ambiguous A::f or B::f
}
}
Run Code Online (Sandbox Code Playgroud) 在[namespace.udecl]/10中,您有以下示例:
namespace A {
int i;
}
namespace A1 {
using A::i;
using A::i; // OK: double declaration
}
void f() {
using A::i;
using A::i; // error: double declaration
}
Run Code Online (Sandbox Code Playgroud)
这个片段编译成clang.
从10.4 抽象类 parag.标准中的6:
"可以从抽象类的构造函数(或析构函数)调用成员函数;直接或间接地对从这样的构造函数(或析构函数)创建(或销毁)的对象进行纯虚函数的虚拟调用的效果未定义."
假设标准允许从构造函数(或析构函数)调用非纯虚函数,为什么区别?
[编辑]关于纯虚函数的更多标准引用:
§10.4/ 2通过在类定义中的函数声明中使用纯说明符(9.2)来指定虚函数.只有在使用(12.4)qualified-id语法(5.1)调用时,才需要定义纯虚函数.... [注意:函数声明不能同时提供纯指定符和定义-end note]
§12.4/ 9 析构函数可以声明为虚拟(10.3)或纯虚拟(10.4); 如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数.
一些需要回答的问题是:
如果纯虚函数没有给出实现,那么这不应该是编译器或链接器错误吗?
在为纯虚函数赋予实现的情况下,为什么在这种情况下不能很好地定义它来调用这个函数?
[basic.def.odr]/3引用了术语"非平凡函数",其定义在标准(N4140)中找不到.
[basic.def.odr]/3
变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,否则将生成一个不调用任何非平凡函数的常量表达式(5.19),并且,如果x是一个对象,ex是表达式e的潜在结果集合的元素,其中左值到右值的转换(4.1)应用于e,或者e是丢弃值表达式(第5节).
friend函数f无权访问封闭类的私有成员A.
#include <iostream>
class A{
const static int p = 1;
class B {
friend void f() {
std::cout << p << '\n';
std::cout << q << '\n';
}
};
public:
const static int q = 2;
};
void f();
int main()
{
f();
}
Run Code Online (Sandbox Code Playgroud)
至少,这是我认为N4140中的[class.nest]/4所说的(见下文).
§9.7/ 4
与成员函数一样,嵌套类中定义的友元函数(11.3)位于该类的词法范围内; 它遵循与名称绑定相同的规则作为该类的静态成员函数(9.4),但它对封闭类的成员没有特殊的访问权限.
抛出对象后,gcc,clang和VS2015不会在下面的代码中忽略对move构造函数的调用a.在我看来,满足§8.12[class.copy]/31(N4140)的项目符号(31.2)中确定的条件.
#include <iostream>
struct A
{
A() { std::cout << "Default ctor " << '\n'; }
A(const A& a) { std::cout << "Copy ctor" << '\n'; }
A(A&& a) { std::cout << "Move ctor" << '\n'; }
~A() { std::cout << "Destructor " << '\n'; }
};
int main()
{
try
{
A a;
throw a;
}
catch(A& a) { std::cout << "Caught" << '\n'; }
}
Run Code Online (Sandbox Code Playgroud)
请注意,这a是一个左值,但根据§12.8/ 32,首先执行重载决策以选择副本的构造函数,就像对象由rvalue指定一样.也就是说,对move构造函数的调用是可以的.如果删除上面的移动构造函数的定义,则调用复制构造函数,但同样,它不会被省略!
我理解标准没有规定复制省略,但我很想知道是否有任何特殊条件可以证明这一事实,上面提到的三个编译器在这个特定的例子中避免了这种优化.
gcc的示例输出,来自上面的链接:
g ++ -std …
clang不编译typeid下面的第三个调用(参见实例).但我在§5.2.8中看不到任何禁止这一点的内容,特别是当我们认为表达式B::f不是多态类类型的glvalue时(见第3段).此外,根据此段,表达式B::f是未评估的操作数,因此,调用typeid(B::f)应该编译.请注意,GCC不会编译以下任何调用typeid:
#include <iostream>
#include <typeinfo>
struct A{ int i; };
struct B{ int i; void f(); };
int main()
{
std::cout << typeid(A::i).name() << '\n';
std::cout << typeid(B::i).name() << '\n';
std::cout << typeid(B::f).name() << '\n';
}
Run Code Online (Sandbox Code Playgroud) 在§5.2[expr.post]/1中,我们有了expression-list的定义
expression-list:
initializer-list
为什么我们需要这两个定义?
在§8.5[dcl.init]/1中,我们有:
braced-init-list:
{initializer-list,opt }
{}
为什么我们需要,上面的可选项?
请注意,此代码段编译:
struct A{
int i;
float f;
A(int i, float f) : i(i), f(f) {}
};
int main()
{
A a = { 1, 2., };
}
Run Code Online (Sandbox Code Playgroud)