Search code examples
c++initializationconstantsinitializerdefault-constructor

How to prevent default initialization of a const variable with a class type


I have a custom class that I want to behave like a built-in type.

However I have noticed that you can initialise a const variable of that class without providing an initial value. My class currently has an empty default constructor.

Here is a comparison of int and my class foo:

int a;              // Valid
int a = 1;          // Valid
const int a = 1;    // Valid
const int a;        // Error

foo a;              // Valid
foo a = 1;          // Valid
const foo a = 1;    // Valid
const foo a;        // Should cause an error, but it compiles

As you can see I need to prevent

const foo a;

from compiling.

Any ideas from C++ gurus?


Solution

  • The rules of C++ simply say that default-initialization (e.g. new T;) and value-initialization (e.g. new T();) are the same for objects of class type, but not for objects of fundamental type.

    There's nothing you can do to "override" this distinction. It's a fundamental part of the grammar. If your class is value-initializable, then it is also default-initializable.

    There is a sort-of exception for classes without any user-defined constructors: In that case, initialization of members is done recursively (so if you default-init the object, it tries to default-init all members), and this will fail if any of the class members are themselves fundamental, or again of this nature.

    For example, consider the following two classes:

    struct Foo { int a; int b; };
    struct Goo { int a; int b; Goo(){} };
    
    //const Foo x; // error
    const Goo y;   // OK
    

    The implicit constructor for Foo is rejected because it doesn't initialize the fundamental members. However, y is happily default-initialized, and y.a and y.b are now "intentionally left blank".

    But unless your class doesn't have any user-defined constructors, this information won't help you. You cannot "forward" the initialization type to a member (like Foo() : INIT_SAME_AS_SELF(a), b() { }).