Overloading reference operator

S

samjam86

Hi,
I overloaded reference operator in a templatized class like below:

template<class T>
MyClass
{
public:
MyClass() : m_data(10) { }
operator T&() { return m_data; }
private:
T m_data;
};
Now I wrote a code to utilize reference operator as below:
int main()
{
MyClass instance;
instance++; // this works fine
++instance; // this too works fine
instance = 105; // this gives compile error. Why ?
return 0;
}

The pre and post increment operators work fine, but a simple
assignment operator is giving compilation error.
Is there a valid reason for this or is this undefined behavior ?

Thank you.

Regards,
Samkit
 
Ö

Öö Tiib

Hi,
I overloaded reference operator in a templatized class like below:

template<class T>
MyClass
{
 public:
    MyClass() : m_data(10) { }
    operator T&() { return m_data; }
 private:
    T m_data;};

Now I wrote a code to utilize reference operator as below:
int main()
{
    MyClass instance;

This already does not compile.
    instance++; // this works fine
    ++instance; // this too works fine
    instance = 105;    // this gives compile error. Why ?
    return 0;

}

The pre and post increment operators work fine, but a simple
assignment operator is giving compilation error.
Is there a valid reason for this or is this undefined behavior ?

We can't help you if you post false claims. http://www.parashift.com/c++-faq-lite/
 
S

Salt_Peter

Hi,
I overloaded reference operator in a templatized class like below:

template<class T>

template said:
MyClass
{
 public:
    MyClass() : m_data(10) { }
    operator T&() { return m_data; }
 private:
    T m_data;};

Now I wrote a code to utilize reference operator as below:
int main()
{
    MyClass instance;
    instance++; // this works fine
    ++instance; // this too works fine
    instance = 105;    // this gives compile error. Why ?

that statement is an assignment.
i don't see any assignment operator that takes a T and neither can the
compiler
    return 0;

}

The pre and post increment operators work fine, but a simple
assignment operator is giving compilation error.
Is there a valid reason for this or is this undefined behavior ?

What do you mean by simple assignment?
If you were to use the silently provided assignment operator - it
would have a signature as follows:
T& operator=(const T& rhv);
 
K

Kai-Uwe Bux

samjam86 said:
Hi,
I overloaded reference operator in a templatized class like below:

template<class T>
MyClass
{
public:
MyClass() : m_data(10) { }
operator T&() { return m_data; }
private:
T m_data;
};
Now I wrote a code to utilize reference operator as below:
int main()
{
MyClass instance;

That line already is wrong.
instance++; // this works fine
++instance; // this too works fine
instance = 105; // this gives compile error. Why ?
return 0;
}

The following compiles and works on my machine:

#include <iostream>

template < typename T >
struct xxx {

T value;

xxx ( T const & v )
: value ( v )
{}

operator T & ( void ) {
return ( value );
}

};

int main ( void ) {
xxx< int > a ( 4 );
a = 5;
std::cout << a << "\n";
}


Best

Kai-Uwe Bux
 
S

sebastian

Hi,
I overloaded reference operator in a templatized class like below:

template<class T>
MyClass
{
 public:
    MyClass() : m_data(10) { }
    operator T&() { return m_data; }
 private:
    T m_data;};

Now I wrote a code to utilize reference operator as below:
int main()
{
    MyClass instance;
    instance++; // this works fine
    ++instance; // this too works fine
    instance = 105;    // this gives compile error. Why ?
    return 0;

}

The pre and post increment operators work fine, but a simple
assignment operator is giving compilation error.
Is there a valid reason for this or is this undefined behavior ?

Thank you.

Regards,
Samkit

The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).
 
C

cpp4ever

The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Perhaps the following will reveal why using an implicit conversion as an
l-value fails, and is not a flaw.

The problem here is there is neither of these 2 member functions are
implemented in the class

MyClass(const T &inp) ( m_data = inp; }
MyClass &operator = (const T &inp) ( m_data = inp; return *this }

both of which provide a method for assignment to MyClass using a
variable of type T. Try it with my updated code sample.

template<class T>
class MyClass
{
public:
MyClass() : m_data(10) { }
//MyClass(const T&inp) { m_data = inp; }
operator T&() { return m_data; }
MyClass &operator=(const T&inp) { m_data = inp;return *this; }
private:
T m_data;
};

int main()
{
MyClass<int> instance;
instance++; // this works fine
++instance; // this too works fine
instance = 105; // this gives compile error. Why ?
return 0;
}

Note the constructor use will not work if it is made explicit.

Hope this clarifies things.

JB
 
K

Kai-Uwe Bux

sebastian wrote:
[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].


Best

Kai-Uwe Bux
 
C

cpp4ever

Perhaps the following will reveal why using an implicit conversion as an
l-value fails, and is not a flaw.

The problem here is there is neither of these 2 member functions are
implemented in the class

MyClass(const T &inp) ( m_data = inp; }
MyClass &operator = (const T &inp) ( m_data = inp; return *this }

both of which provide a method for assignment to MyClass using a
variable of type T. Try it with my updated code sample.

template<class T>
class MyClass
{
public:
MyClass() : m_data(10) { }
//MyClass(const T&inp) { m_data = inp; }
operator T&() { return m_data; }
MyClass &operator=(const T&inp) { m_data = inp;return *this; }
private:
T m_data;
};

int main()
{
MyClass<int> instance;
instance++; // this works fine
++instance; // this too works fine
instance = 105; // this gives compile error. Why ?
return 0;
}

Note the constructor use will not work if it is made explicit.

Hope this clarifies things.

JB

IMHO it is better practice to implement the prefix/postfix increment
operators for a class rather than relying on a cast operator. In this
case the cast was unambiguous as only one possible cast could be used.
Using a direct implementation of the prefix/postfix increment operators
avoids that problem.

JB
 
C

cpp4ever

sebastian wrote:
[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].


Best

Kai-Uwe Bux

It makes sense, the purpose of casting, consider

int iTmp;
static_cast<float>(iTmp) = 3.16

This is obvious nonsense, as opposed to doing a conversion before
parsing to a function. So if the prefix/postfix increment operators are
considered to be functions then the conversion is done before being parsed.

I've not looked in the standard yet, but this may give a hint about
where to look.

Hope this makes sense.

JB
 
C

cpp4ever

sebastian wrote:
[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].


Best

Kai-Uwe Bux

It makes sense, the purpose of casting, consider

int iTmp;
static_cast<float>(iTmp) = 3.16

This is obvious nonsense, as opposed to doing a conversion before
parsing to a function. So if the prefix/postfix increment operators are
considered to be functions then the conversion is done before being parsed.

I've not looked in the standard yet, but this may give a hint about
where to look.

Hope this makes sense.

JB

This worked in the example I gave without the other member functions

static_cast<int &>(instance) = 123;

But this is equivalent to calling the cast operator, and as the result
is a reference it can be used as an l-value.

I admit I'd never thought about doing this sort of operation, but it
makes sense. Even if it's somewhat confusing to folks less familiar with
C++.

Am I too geeky?

JB
 
C

cpp4ever

sebastian wrote:
[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].


Best

Kai-Uwe Bux

try section 4 paragraph 2, this deals with when implicit conversions
will be attempted.

:) I am too geeky

JB
 
K

Kai-Uwe Bux

cpp4ever said:
sebastian wrote:
[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].


Best

Kai-Uwe Bux

try section 4 paragraph 2, this deals with when implicit conversions
will be attempted.

If read:

[Note: expressions with a given type will be implicitly converted to other
types in several contexts:
? When used as operands of operators. The operator?s requirements for its
operands dictate the destination type (clause 5).
...

a) [4/2] is a non-normative note.
b) From context, it might just talk about standard conversions, which only
apply to built-in types.
c) From the beginning that I quoted, it seems clear that operator=, just
like other operators, can trigger an implicit conversion.
d) There seems to be nothing about l-values in [4/2].

So, I am still in the dark.


Best regards,

Kai-Uwe Bux
 
Ö

Öö Tiib

sebastian wrote:

[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].

[basic.lval]/6 say that result of conversion of non-reference type is
rvalue. I think there is no difference if it is implicit or explicit
conversion.
 
K

Kai-Uwe Bux

Öö Tiib said:
sebastian wrote:

[...]
The result of the implicit conversion operator can't be used as an l-
value, unfortunately (major language flaw, IMO).

Could you provide the clause in the standard for that? I didn't find it
anywhere in section [12.3.2].

[basic.lval]/6 say that result of conversion of non-reference type is
rvalue. I think there is no difference if it is implicit or explicit
conversion.

Here is [3.10/6] ([3.10] is [basic.lval]):

An expression which holds a temporary object resulting from a cast to a
nonreference type is an rvalue (this includes the explicit creation of an
object using functional notation (5.2.3)).

The cast is required to go _to_ a non-reference type (your wording made it
sound as though the provision applies to a conversion _from_ a non-reference
type). So I don't see how that applies to:

operator T& ( void ) {...}

Maybe, you meant a different provision?


Best

Kai-Uwe Bux
 
Ö

Öö Tiib

Öö Tiib said:
[basic.lval]/6 say that result of conversion of non-reference type is
rvalue. I think there is no difference if it is implicit or explicit
conversion.

Here is [3.10/6] ([3.10] is [basic.lval]):

  An expression which holds a temporary object resulting from a cast to a
  nonreference type is an rvalue (this includes the explicit creation of an
  object using functional notation (5.2.3)).

The cast is required to go _to_ a non-reference type (your wording made it
sound as though the provision applies to a conversion _from_ a non-reference
type).

Yep. I did misread myself. Ok. Then my best bet is that something in
[13.3.1.2] is on our way.
Hmm.
My copy of standard claims:
<quote [13.3.1.2]/4>
For the built-in assignment operators, conversions of the left operand
are restricted as follows:

— no temporaries are introduced to hold the left operand, and

— no user-defined conversions are applied to the left operand to
achieve a type match with the left-most parameter of a built-in
candidate.
</quote>

No user T& operator applied to left guy since int = int is built in
assignment operator, yes?
 
P

Paul Bibbings

Öö Tiib said:
Öö Tiib said:
[basic.lval]/6 say that result of conversion of non-reference type is
rvalue. I think there is no difference if it is implicit or explicit
conversion.

Here is [3.10/6] ([3.10] is [basic.lval]):

  An expression which holds a temporary object resulting from a cast to a
  nonreference type is an rvalue (this includes the explicit creation of an
  object using functional notation (5.2.3)).

The cast is required to go _to_ a non-reference type (your wording made it
sound as though the provision applies to a conversion _from_ a non-reference
type).

Yep. I did misread myself. Ok. Then my best bet is that something in
[13.3.1.2] is on our way.
Hmm.
My copy of standard claims:
<quote [13.3.1.2]/4>
For the built-in assignment operators, conversions of the left operand
are restricted as follows:

— no temporaries are introduced to hold the left operand, and

— no user-defined conversions are applied to the left operand to
achieve a type match with the left-most parameter of a built-in
candidate.
</quote>

No user T& operator applied to left guy since int = int is built in
assignment operator, yes?

I'm assuming that we're still referring to the OP's code here which,
corrected (and reduced), was:

template<class T>
class MyClass
{
public:
MyClass() : m_data(10) { }
operator T&() { return m_data; }
private:
T m_data;
};

int main()
{
MyClass<int> instance;
// <snip />
instance = 105; // this gives compile error. Why ?
return 0;
}

In this context, I think that §13.3.1.2/4 is indeed what prevents this
from working. With no user-defined assignment operator, only built-in
operators are available. The built-in:

int& operator=(int&, int)

won't be considered because, according to §13.3.1.2/4, "no user-defined
conversions are applied to the left operand to achieve a type match with
the left-most parameter of a built-in candidate," as you suggest.

Regards

Paul Bibbings
 
K

Kai-Uwe Bux

Öö Tiib said:
Öö Tiib said:
[basic.lval]/6 say that result of conversion of non-reference type is
rvalue. I think there is no difference if it is implicit or explicit
conversion.

Here is [3.10/6] ([3.10] is [basic.lval]):

An expression which holds a temporary object resulting from a cast to a
nonreference type is an rvalue (this includes the explicit creation of an
object using functional notation (5.2.3)).

The cast is required to go _to_ a non-reference type (your wording made
it sound as though the provision applies to a conversion _from_ a
non-reference type).

Yep. I did misread myself. Ok. Then my best bet is that something in
[13.3.1.2] is on our way.
Hmm.
My copy of standard claims:
<quote [13.3.1.2]/4>
For the built-in assignment operators, conversions of the left operand
are restricted as follows:

? no temporaries are introduced to hold the left operand, and

? no user-defined conversions are applied to the left operand to
achieve a type match with the left-most parameter of a built-in
candidate.
</quote>

No user T& operator applied to left guy since int = int is built in
assignment operator, yes?

Not sure. Sounds convincing. What disturbs me is that g++ and Comeau accept
the following:

#include <iostream>

template < typename T >
struct xxx {

T value;

xxx ( T const & v )
: value ( v )
{}

operator T & ( void ) {
return ( value );
}

};

int main ( void ) {
xxx< int > a ( 4 );
a = 5;
std::cout << a << "\n";
}


Hm, have to think (and maybe to file bug reports).


Many thanks,

Kai-Uwe Bux
 
Ö

Öö Tiib

Öö Tiib said:
Öö Tiib wrote:
[basic.lval]/6 say that result of conversion of non-reference type is
rvalue. I think there is no difference if it is implicit or explicit
conversion.
Here is [3.10/6] ([3.10] is [basic.lval]):
An expression which holds a temporary object resulting from a cast to a
nonreference type is an rvalue (this includes the explicit creation of an
object using functional notation (5.2.3)).
The cast is required to go _to_ a non-reference type (your wording made
it sound as though the provision applies to a conversion _from_ a
non-reference type).
Yep. I did misread myself. Ok. Then my best bet is that something in
[13.3.1.2] is on our way.
Hmm.
My copy of standard claims:
<quote [13.3.1.2]/4>
For the built-in assignment operators, conversions of the left operand
are restricted as follows:
    ? no temporaries are introduced to hold the left operand, and
    ? no user-defined conversions are applied to the left operand to
achieve a type match with the left-most parameter of a built-in
candidate.
</quote>
No user T& operator applied to left guy since int = int is built in
assignment operator, yes?

Not sure. Sounds convincing. What disturbs me is that g++ and Comeau accept
the following:

#include <iostream>

template < typename T >
struct xxx {

  T value;

  xxx ( T const & v )
    : value ( v )
  {}

  operator T & ( void ) {
    return ( value );
  }

};

int main ( void ) {
  xxx< int > a ( 4 );
  a = 5;
  std::cout << a << "\n";

}

Hm, have to think (and maybe to file bug reports).

Nope, it is valid code. There is default:

xxx& xxx::eek:perator =( xxx const& );

It is useful since applying converson to right '5' is possible and
left 'a' needs not to be converted.
 
K

Kai-Uwe Bux

Öö Tiib said:
Nope, it is valid code. There is default:

xxx& xxx::eek:perator =( xxx const& );

It is useful since applying converson to right '5' is possible and
left 'a' needs not to be converted.

Ah, I see.

Thanks,

Kai-Uwe Bux
 
V

Victor Bazarov

[..] What disturbs me is that g++ and Comeau accept
the following:

#include<iostream>

template< typename T>
struct xxx {

T value;

xxx ( T const& v )
: value ( v )
{}

operator T& ( void ) {
return ( value );
}

};

int main ( void ) {
xxx< int> a ( 4 );
a = 5;
std::cout<< a<< "\n";
}


Hm, have to think (and maybe to file bug reports).

Why? The statement

a = 5;

is in fact

a.operator =( xxx<int>(5) ); // compiler-generated assignment

where the argument is a temporary created using your user-defined
conversion from int to xxx<int> (via the constructor). The compiler
applies the conversion to the *right* side, not to the left.

Try declaring a private assignment op in 'xxx'.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,067
Latest member
HunterTere

Latest Threads

Top