Question

Its unclear to me whether a temporary assumes type of const or not, in an expression as shown below.

#include <iostream>

class X {
public:
X(int a) { i = a; cout << "X(int) [" << (int)this << "]" << endl; }

X& operator+(const X& x) 
{ 
i += x.i; 
cout << "X operator+(const X&) [" << (int)this << "]" << endl; 
return *this; 
}

~X() { cout << "~X [" << (int)this << "]" << endl; }

private:
int i;
};


int main() 
{
X x = X(3) + X(4);
cout << "done" << endl;

return 0;
}

X(3) behaves like non-const (because I can call operator+, while X(4) behaves like const(because, it needs const argument in operator+).

Can someone clarify, what is the right understanding?

Was it helpful?

Solution

When it comes to class types, when you create a temporary of const type, that temporary will be const. And when you create a temporary of non-const type, that temporary will be non-const. That's it. I.e. as far as the exact type is concerned, there no connection between const and temporaries at all. Temporary of class type never assumes const by itself. It is you who can explicitly impose const on it.

In your example nether X(3) nor X(4) is const. Since X(3) is not const, you can call a non-const method on it.

It is not correct to say that your X(4) "behaves as const". There's no indication that it "behaves as const" in your example whatsoever. Just because you were able to initialize a const reference with something does no mean that that something is const.

In your question you state that you "need const argument in operator+". That's incorrect. You don't need const argument in your operator+. Your parameter x is declared as const reference. A const reference can be easily bound to const arguments as well as to non-const arguments. In your case const reference parameter x is bound to a non-const temporary argument X(4).

OTHER TIPS

You can call non-const members of temporaries. But you cannot bind a non-const reference to a temporary.

Historically, temporaries are rvalues, and rvalues aren't (and can't be) cv-qualified. This rule worked well for non-class types, or for class types with no member functions; since const-ness intervenes in function overload resolution, the cv-qualification of a temporary must be maintained. If a function returns simply X, then the temporary is not const, and you can call non-const functions on it; if the functions returns X const, then the temporary is const, and you can't call non-const functions on it. As a general rule, it's probably preferable to return class types as const; i.e. X const f(), rather than X f(). But there are definitely exceptions, and no body does it, even in the cases where it would be more appropriate. And finally, there are contexts where you can't specify the const-ness—function style type conversions, for example—where the syntax doesn't provide a means of specifying cv-qualifiers (except by using typedef's).

You might want to look at the output from the following code:

class C
{
    std::string myComment;
public:
    C( std::string const& comment ) : myComment( comment ) {}

    void f()
    {
        std::cout << "Non const " << myComment << std::endl;
    }

    void f() const
    {
        std::cout << "Const " << myComment << std::endl;
    }
};

typedef C const CC;

C
c()
{
    return C("function return value");
}

C const
cc()
{
    return C("function return value");
}

int
main()
{
    C("function style conversion").f();
    CC("function style conversion").f();
    c().f();
    cc().f();
}

In the following code:

X x = X(3) + X(4);

X(3) creates a temporary non-const object which invokes operator+, passing X(4) which is another temporary non-const object as const reference argument to the function.

A non-const object can be passed to a function as const object (passing by reference), but a const object cannot be passed by non-const reference to a function. That is the difference.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top