2

I would like to break the compilation if the object is declared const.

The following doesn't work :

#include <type_traits>

struct A {

    A() : v(0)
    {
        static_assert( ! std::is_const<decltype(*this)>::value, "declared as const" );
    }

    int& AccessValue() const
    {
        return const_cast< int& >( v );
    }

    int v;
};

int main()
{
    A a1; // ok, this compiles
    const A a2; // no, this break the compilation

    a1.AccessValue() = 5; // ok
    a2.AccessValue() = 6; // OPS
}

So, is there a way to break the compilation if an object of this type is declared const?

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • 5
    I doubt it is possible. What do you want to achieve ? – Alexandre C. Mar 27 '12 at 13:13
  • 1
    If someone gets a `const A` but shouldn't, the compiler will eventually give errors basically saying the same thing (declared as const), so you don't really need to check for such things. – Shahbaz Mar 27 '12 at 13:17
  • @AlexandreC. It is UB to use const_cast to change from const reference to non-const reference, unless the object is declared non-const. I need to use const_cast, but would like to prevent people from declaring objects of this type const. – BЈовић Mar 27 '12 at 13:22
  • 2
    @VJovic If that were possible I guess compilers would already check it, since that’s a very useful and obvious diagnostic to do before `const_cast`. – Konrad Rudolph Mar 27 '12 at 13:26
  • 2
    @VJovic: You should probably redirect your efforts to avoid the need of `const_cast`. That is, the better questions are: Why do you **need** `const_cast`? How can you **avoid** using `const_cast`? – David Rodríguez - dribeas Mar 27 '12 at 13:32
  • I modified my example to demonstrate what I mean. Instead of int, it should be some complex class. If you think it's not possible, then it should be an answer, no? – BЈовић Mar 27 '12 at 13:32
  • @VJovic: wouldn't making `i` mutable achieve what you want without the cast? – Mat Mar 27 '12 at 13:36
  • @Mat I am not sure if changing the value using the `AccessTheValue()` method is UB or not. EDIT : Found it [dcl.type.cv]/4 says it is ok to modify method variable declared as mutable. Thanks – BЈовић Mar 27 '12 at 13:43
  • @VJovic: as `Mat` said, it is not UB if `i` is `mutable`. – Matthieu M. Mar 27 '12 at 13:45

3 Answers3

3

You are heading the wrong way.

The type of this is purely dictacted by the signature of the method in which you use it. That is, this is always of type cv T* const where cv corresponds to the CV qualifiers of the method.

Therefore, in a constructor, this is just T* const.


const_cast is a code smell, normally only of use when dealing with const-broken legacy libraries... or (sometimes) to avoid violating DRY. In new code, you should not have to use it.

You are left with a choice:

  • make AccessValue non-const, since it is not
  • declare i as being mutable.

I would advise choosing the former solution. Giving away a handle to a private attribute is bad already (breaks encapsulation), no need to violate const correctness as well.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 2
    `this` is never `U const`. It is an rvalue. `const` doesn't make sense for non-object rvalues, so there are no non-class/non-array rvalues of that type – Johannes Schaub - litb Mar 27 '12 at 21:01
  • @JohannesSchaub-litb: this, I guess, it the legalese approach. In practice [it is qualified](http://ideone.com/Gzgyg). Perhaps because this helps the compiler diagnosing ill-formed calls ? (avoiding the addition of extraneous logic for `this`) – Matthieu M. Mar 28 '12 at 06:29
  • if you pass "this" to a template and deduce its type and gcc deduces it as "U const" you not only have a confusing diagnostic (btw, a diagnostic that says "this" has type "U const" doesnt mean that it really has that type) but an actual bug. Some compilers also talk about expressions that have type "U &" when they wanna tell the user that it is an lvalue of type "U". – Johannes Schaub - litb Mar 28 '12 at 06:44
  • @JohannesSchaub-litb: so should we considered there is a bug in [gcc 4.3.4](http://ideone.com/NWpyr) and [gcc 4.5.2](http://ideone.com/BCNWP) ? – Matthieu M. Mar 28 '12 at 08:11
  • @MatthieuM.: Yes, all those should print "none". Compiler should implement `this` by substituting it with `(__this + 0)`, where `__this` is the actual `this` value. The `+ 0` makes it an rvalue. (Johannes showed me this idea.) – GManNickG Mar 28 '12 at 22:02
  • @GManNickG: I think I actually misinterpreted Johannes' comment (I tend to do that a lot). It makes sense for `this` to point to `const` or `volatile` objects, what does not make sense is for `this` itself to be `const`. And my examples never covered this case. Apparently, gcc (at least) correctly treats it as an rvalue: http://ideone.com/qfs7h – Matthieu M. Mar 29 '12 at 06:16
  • @MatthieuM.: Oh, and I even misread your tests. Well I'm glad we're both clear now. :) – GManNickG Mar 29 '12 at 06:22
1

For your specific example, making i mutable would achieve your goal:

int& AccessValue() const
{
    return v;
}

mutable int v;

This is from §7.1.6.1/4 [dcl.type.cv]:

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.

Note that you can't modify v using a pointer-to-member on a const object - §5.5/5 of n3290 draft [expr.mptr.oper]:

[ Note: it is not possible to use a pointer to member that refers to a mutable member to modify a const class object. For example,

struct S {
S() : i(0) { }
mutable int i;
};

void f()
{
const S cs;
int S::* pm = &S::i; // pm refers to mutable member S::i
cs.*pm = 88;         // ill-formed: cs is a const object
}

— end note ]

Mat
  • 202,337
  • 40
  • 393
  • 406
  • But I don't have pointer to member variable. Therefore [7.1.6.1/5, latest c++11] applies, there it is allowed to change it. There is even an example – BЈовић Mar 27 '12 at 13:56
  • Yes, the mutable member works. I was just pointing out that there are some things you can't do even though the member is mutable - using a pointer to member specifically. But as long as you don't do that it is good. – Mat Mar 27 '12 at 13:57
0

you can have multiple variables referring to the same object, some mutable and some const. For example:

A a1;
const A &a2 = a1;
A * const pa = &a1;
f(a1);
....
void f(const A &a);

should these be allowed in your case? Conversion from mutable to const is implicit the reverse is not. Maybe if you give an example will help.

EDIT: (in response to modified code) with a const object you can call only const member function. why not have:

int& AccessValue()
{
    return v;
}

an the compiler with complain if you call AccessValue on a non const object.

Marius
  • 833
  • 5
  • 11