Take the 2-minute tour ×

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?

share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

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() { }).

share|improve this answer
In the first sentence, fundamental type should be changed to POD type, which includes fundamental types and other types that fit --to some extent-- your description in the third paragraph. Also note that the third paragraph is also not precise in the description of which types fall under that category: the presence of a member of fundamental type does not change the behavior, but rather the absence of a non-POD member, and it is also missing the fact that a type with only fundamental types and a virtual function will also imply that new T; and new T(); are equivalent... –  David Rodríguez - dribeas Nov 18 '11 at 14:23
@DavidRodríguez-dribeas: No, POD isn't right. Your class may well have non-POD members and still behave this way. Perhaps "aggregate", but I think it's only the absence of a user constructor. E.g. having a destructor doesn't change this. Try adding a std::string member or a destructor. I think the recursive definition using the implied constructor is the most universal and concise. –  Kerrek SB Nov 18 '11 at 14:25
@DavidRodríguez-dribeas: I don't think any of what you said is correct: Try struct Foo { std::string a; virtual void f() { }; ~Foo() {} }; Now const Foo x; still doesn't work, but const Foo x{}; does. –  Kerrek SB Nov 18 '11 at 14:29
struct test1 { std::string s; int i; }; const test1 t; compiles. struct test2 { int i; virtual void f() {} }; const test2 t; compiles. You are right in that destructors do not affect the problem, so POD is not the best definition, but your definitions above aren't either. The example that you provide in your last comment compiles fine for me (g++4.6, c++03 mode) and for ideone in both c++ and c++11 modes. What compiler have you tried? –  David Rodríguez - dribeas Nov 18 '11 at 19:28
@DavidRodríguez-dribeas: That's GCC 4.6.2, with or without -std=c++0x. –  Kerrek SB Nov 18 '11 at 19:30
show 4 more comments

It compiles only if it has a default constructor, and it compiles because it has it, which means that it is initialized. If you don't want that line to compile, just disable the default constructor (will also make foo a; an error as an unwanted side effect). Without a definition of foo or what you want to do, this is as far as I can get.

I don't think there is any way of achieving what you want (i.e. allow the non-const variable to be default initialized, while having the const version fail compilation and allowing the other use cases --that require providing constructors)

share|improve this answer
You could make the default constructor protected. –  arne Nov 18 '11 at 12:24
@arne: I don't see how that would help. Either the default constructor is accessible and both foo a; const foo a; compile, or it is not and neither compiles. Additionally, protected would probably not be the best approach, since there is no inheritance in the question, the natural choices would be public to grant access and private to forbid it. –  David Rodríguez - dribeas Nov 18 '11 at 12:27
@arne: That would achieve what? protected visibility is only useful in inheritance scenarios. –  Xeo Nov 18 '11 at 12:27
add comment

Your Answer


