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 Standard (ISO/IEC 14882:2011), Section 3.9, Paragraph 10 states (emphasis mine):

A type is a literal type if it is:

  • a scalar type; or
  • a reference type; or
  • a class type (Clause 9) that has all of the following properties:
    • it has a trivial destructor,
    • every constructor call and full-expression in the brace-or-equal-initializers for non-static data members (if any) is a constant expression (5.19),
    • it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
    • it has all non-static data members and base classes of literal types; or
  • an array of literal type.

In my opinion, taking into account the bullet in bold, class A is not a literal type in C++11 because there are constructor calls and a brace-or-equal-initializers for non-static data members that are not constant expressions. I tried putting constexpr before the constructor definition and also assigning the constructor call to a constexpr variable to check that indeed the compiler complains because those are not constant expressions. However, both Clang and GCC compile it successfully. So I am probably wrong.

  • Does anyone know why class A is a literal type?

The bullet in bold was removed in C++14 (N3652), so I understand class A is a literal type in C++14. I need to know because function is constexpr, therefore each of its parameter types shall be a literal type (C++11/C++14 Standard, Section 7.1.15, Paragraph 3).

EDIT: In the Original Post I used a simple example to make it easier to read, and explained I already tried many combinations. Now I updated the example with some of those combinations to show I tried different constructor calls, definitions and non-static data member initializations. Thanks.

10
  • "Does anyone know why class A is a literal type?" It isn't in C++11. And none of the code you've shown requires it to be a literal type. So what's the problem? Commented Feb 2, 2017 at 15:11
  • Do you know what a brace-or-equal-initializer is? Commented Feb 2, 2017 at 15:45
  • @T.C. I think brace-or-equal initializer is this int x {y} or this int x = y. I usually say member-initializer-list for the initializations in the constructor like when initializing value in A( int z ) : value( x ) {}, but I have also read a lot of people referring this like brace-or-equal initializer. Please correct me if I made any mistake. In any case, I tried many combinations of braces, equals, etc. initializations both for the object itself and for the variable value in the constructor, and the result is the same. Thanks. Commented Feb 2, 2017 at 16:09
  • @NicolBolas Section 7.1.15, Paragraph 3 of the C++11 and C++14 Standard states, referring to a constexpr function that each of its parameter types shall be a literal type. That is where it is required in constexpr int function( A obj ){ return 1; }. The problem is that both you and me think class A is not a literal type, but both Clang and GCC compile it like it is. So maybe we are missing something. Thanks. Commented Feb 2, 2017 at 16:14
  • 2
    Core issue 1361. "We resolve DR1361 by ignoring the second bullet." Commented Feb 3, 2017 at 12:12

1 Answer 1

5

Does anyone know why class A is a literal type?

It's not in C++11, but it is in C++14, for the reasons you cite in your post. However...

However, both Clang and GCC compile it successfully. So I am probably wrong.

You are not wrong. Neither are clang and gcc. The code is, indeed, well-formed despite A not being a literal type... simply because nothing requires it to be a literal type. function may be a constexpr function, but it isn't being invoked as a constant expression. var isn't a constexpr object, so there's no enforced requirement that all the objects be of literal type. Had you tried:

constexpr int var = function(...);

then the code would be ill-formed, as in this case, function(...) would need to be a core constant expression, which requires literal types, which is a requirement that in C++11 A failed. (Actually, you'd also have the problem in C++14 that none of the As are constexpr objects).

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.