C++11/C++14中的字面量类型类

9
int x = 1; // Not Constant

class A {
    public:
        int value  = x;
        int value2 { x };
        A( int a )        : value( x ), value2( x ) {}
        A( int a, int b ) : value{ x }, value2{ x } {}
        constexpr A() : value{ 0 }, value2{ 0 } {}
};

constexpr int function( A obj1, A obj2, A obj3, A obj4, A obj5, A obj6, A obj7 ){ 
    return 1; 
}

int main(){

    int y = 2; // Not Constant
    A obj1   ( y );
    A obj2   { y };
    A obj3 =   y  ;
    A obj4 = { y };
    A obj5   ( y, y );
    A obj6   { y, y );
    A obj7 = { y, y };
    int var = function( obj1, obj2, obj3, obj4, obj5, obj6, obj7 );

    return 0;
}

C++11标准(ISO/IEC 14882:2011),第3.9节,第10段陈述(强调我):
如果类型满足以下条件,则它是字面类型
  • 标量类型;或者
  • 引用类型;或者
  • 类类型(第9条款),具有以下所有属性:
    • 它具有平凡析构函数,
    • 对于非静态数据成员(如果有)的大括号或等于初始化器中的每个构造函数调用和完整表达式都是常量表达式(5.19),
    • 它是聚合类型(8.5.1)或具有至少一个不是复制或移动构造函数的constexpr构造函数或构造函数模板,并且
    • 它具有所有字面类型的非静态数据成员和基类;或者
  • 字面类型的数组。
在我看来,考虑到粗体字中的子弹点,class A 在 C++11 中不是字面类型,因为对于非静态数据成员,存在构造函数调用和大括号或等号初始化器,这些都不是常量表达式。我尝试在构造函数定义前加上constexpr,并将构造函数调用分配给一个constexpr变量,以检查编译器是否会抱怨,因为这些都不是常量表达式。然而,Clang 和 GCC 都可以成功编译它。所以我可能是错的。
  • 是否有人知道为什么class A 是字面类型?

粗体字中的子弹点已在 C++14 中被删除(N3652),因此我理解 class A 在 C++14 中是字面类型。我需要知道这一点,因为 functionconstexpr,因此 其每个参数类型都必须是字面类型(C++11/C++14 标准,第 7.1.15 节,第 3 段)。

编辑:在原帖中,我使用了一个简单的例子来使其更易于阅读,并解释了我已经尝试了许多组合。现在,我更新了这个例子,展示了我尝试了不同的构造函数调用、定义和非静态数据成员初始化。谢谢。


有人知道为什么A类是字面类型吗?这在C++11中并不是这样。而且你展示的代码都不需要它成为字面类型。所以问题出在哪里? - Nicol Bolas
@JL:但是这行已经被注释了,所以不会影响编译。你应该把这行取消注释。 - Nicol Bolas
@NicolBolas 我知道,我评论它是因为那不是主要问题,并且为了使代码更易于阅读。我的主要问题是 class A 是否是字面类型以及为什么。但我也会取消对该代码的注释。谢谢。 - J L
2
“核心问题1361”(http://wg21.link/cwg1361)。 “我们通过忽略第二个要点来解决DR1361。”(https://github.com/llvm-mirror/clang/blob/fe32c6a33461a8c60e18c0414d4844a47442328a/lib/AST/Type.cpp#L2239) - T.C.
@T.C. 你说得对,你所说的一切都很有道理,所以我想我只是没有理解粗体弹头(3.9/10)。我也读了你告诉我的内容,但我不明白它与我的例子有什么关系:我有两个构造函数不是constexpr,因此它们不必遵守constexpr构造函数的规则。无论如何,我的程序正在工作,所以没有问题,我只是好奇因为我喜欢学习。再次感谢您的帮助。 - J L
显示剩余5条评论
1个回答

5
有人知道为什么类 A 是一个字面类型吗?
在C++11中它不是,但在C++14中是,正如您在帖子中引用的原因。然而...
然而,Clang和GCC都可以成功编译它。所以我可能是错的。
你没有错。clang和gcc也没有错。该代码确实是良好形式的,尽管 A 不是一个字面类型......只是因为没有要求它成为字面类型。function 可能是一个 constexpr 函数,但它没有作为常量表达式被调用。 var 不是一个 constexpr 对象,因此没有强制要求所有对象都是字面类型。如果你尝试过:
constexpr int var = function(...);

如果这样的话,代码将不合法,因为在这种情况下,function(...)需要是核心常量表达式,需要字面类型,而在 C++11 中,A 不符合此要求。(实际上,在 C++14 中,A 中没有任何一个是 constexpr 对象,这也会导致问题)。

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