Topic: Use of operator T const& to get a reference to self
Author: "James Kanze" <james.kanze@gmail.com>
Date: Wed, 28 Mar 2007 12:20:24 CST Raw View
Given the following program:
#include <locale>
class FG
{
public:
explicit FG( std::locale const& l )
: myLoc( &l ) {}
template< typename F >
operator F const&() const
{
return get< F >( *myLoc, &std::use_facet ) ;
}
private:
std::locale const* myLoc ;
template< typename F >
F const& get( std::locale const& l,
F const& (*f)( std::locale const& ) ) const
{
return (*f)( l ) ;
}
} ;
FG
getF( std::locale const& l )
{
return FG( l ) ;
}
void
f()
{
std::ctype< char > const& ct = getF( std::locale() ) ;
}
G++ (4.1.0) instantates the template operator F const& to get
the const reference needed to call the copy constructor (which
of course fails to compile, since use_facet<FG> is not legal).
Providing a non-template:
operator FG const&() const { return *this ; }
solves the problem, but is g++ correct here? I would have
expected the temporary "FG( l )" to bind directly to the const
reference of the (compiler generated) copy constructor.
Or maybe my question is: is this intentional? Given 8.5.3/5,
"[...]If the initializer expression [...]-- has a class type [it
does] and can be implicitly converted to an lvalue of type "cv3
T3", where "cv1 T1" is reference-compatible with "cv3 T3" [...]
then [...] the reference is bound to the lvalue result of the
conversion [...]" But it doesn't seem at all natural to have a
user defined conversion called for a copy.
--
James Kanze (GABI Software) mailto:james.kanze@gmail.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "=?iso-8859-1?q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Thu, 29 Mar 2007 13:52:02 CST Raw View
James Kanze schrieb:
> Given the following program:
>
> #include <locale>
>
> class FG
> {
> public:
> explicit FG( std::locale const& l )
> : myLoc( &l ) {}
>
> template< typename F >
> operator F const&() const
> {
> return get< F >( *myLoc, &std::use_facet ) ;
> }
>
> private:
> std::locale const* myLoc ;
>
> template< typename F >
> F const& get( std::locale const& l,
> F const& (*f)( std::locale const& ) ) const
> {
> return (*f)( l ) ;
> }
> } ;
>
>
> FG
> getF( std::locale const& l )
> {
> return FG( l ) ;
> }
>
> void
> f()
> {
> std::ctype< char > const& ct = getF( std::locale() ) ;
> }
>
> G++ (4.1.0) instantates the template operator F const& to get
> the const reference needed to call the copy constructor (which
> of course fails to compile, since use_facet<FG> is not legal).
> Providing a non-template:
>
> operator FG const&() const { return *this ; }
>
> solves the problem, but is g++ correct here? I would have
> expected the temporary "FG( l )" to bind directly to the const
> reference of the (compiler generated) copy constructor.
>
> Or maybe my question is: is this intentional? Given 8.5.3/5,
> "[...]If the initializer expression [...]-- has a class type [it
> does] and can be implicitly converted to an lvalue of type "cv3
> T3", where "cv1 T1" is reference-compatible with "cv3 T3" [...]
> then [...] the reference is bound to the lvalue result of the
> conversion [...]" But it doesn't seem at all natural to have a
> user defined conversion called for a copy.
An interesting question, but IMO the standard is quite clear
here, because 12.3.2/1 says unambigiously:
"[..] A conversion function is never used to convert a (possibly
cv-qualified) object to the (possibly cv-qualified) same object
type (or a reference to it),[..]"
This sentence exists since the 1998 standard and has also
not changed in the current draft. I considered for a while that
gcc might not view a temporary as an object, but this seems
also rather clearly expressed in both 1.8 and 12.2.
I observed that even my quite old mingw gcc 3.4, a rather old
Borland Compiler (I just can't find its version number) and
MS-VS2003 show the unexpected behaviour you mention.
But no newer compiler I tested (including all public available
Comeau online versions and MS-VS2005-SP1) did. Of course
we have no majoritarian decision here, but I tend to say that
the standard is unusually unmistakable here ;-)
All newer compilers follow rather strict the mentioned rule:
To enforce this, I simply added the operator FG(FG&) to your
class and none (except the older ones) tried the conversion
operator but gave up with something like "class "FG" has no
suitable copy constructor".
As a not very relevant sidenode: Even by using the language
extension mode of MS-VS2005 the compiler did not do that
but selected instead the actually forbidden FG(FG&) c'tor with
a corresponding warning
"nonstandard extension used : 'argument' : conversion from 'FG'
to 'FG &' A non-const reference may only be bound to an lvalue;
copy constructor takes a reference to non-const") warning).
Concluding, I would say that a bug report for gcc seems a
reasonable choice.
Greetings from Bremen,
Daniel
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "James Kanze" <james.kanze@gmail.com>
Date: Fri, 30 Mar 2007 11:25:09 CST Raw View
On Mar 29, 9:52 pm, "Daniel Kr gler" <daniel.krueg...@googlemail.com>
wrote:
> James Kanze schrieb:
> > Given the following program:
> > #include <locale>
> > class FG
> > {
> > public:
> > explicit FG( std::locale const& l )
> > : myLoc( &l ) {}
> > template< typename F >
> > operator F const&() const
> > {
> > return get< F >( *myLoc, &std::use_facet ) ;
> > }
> > private:
> > std::locale const* myLoc ;
> > template< typename F >
> > F const& get( std::locale const& l,
> > F const& (*f)( std::locale const& ) ) const
> > {
> > return (*f)( l ) ;
> > }
> > } ;
> > FG
> > getF( std::locale const& l )
> > {
> > return FG( l ) ;
> > }
> > void
> > f()
> > {
> > std::ctype< char > const& ct = getF( std::locale() ) ;
> > }
> > G++ (4.1.0) instantates the template operator F const& to get
> > the const reference needed to call the copy constructor (which
> > of course fails to compile, since use_facet<FG> is not legal).
> > Providing a non-template:
> > operator FG const&() const { return *this ; }
> > solves the problem, but is g++ correct here? I would have
> > expected the temporary "FG( l )" to bind directly to the const
> > reference of the (compiler generated) copy constructor.
> > Or maybe my question is: is this intentional? Given 8.5.3/5,
> > "[...]If the initializer expression [...]-- has a class type [it
> > does] and can be implicitly converted to an lvalue of type "cv3
> > T3", where "cv1 T1" is reference-compatible with "cv3 T3" [...]
> > then [...] the reference is bound to the lvalue result of the
> > conversion [...]" But it doesn't seem at all natural to have a
> > user defined conversion called for a copy.
> An interesting question, but IMO the standard is quite clear
> here, because 12.3.2/1 says unambigiously:
> "[..] A conversion function is never used to convert a (possibly
> cv-qualified) object to the (possibly cv-qualified) same object
> type (or a reference to it),[..]"
OK. That's the sentence I was looking for. Unless there's
something I've misunderstood, I'm copying FG, and the conversion
operator was being used to initialize the FG const& parameter of
the (implicitly declared and defined) copy constructor.
> This sentence exists since the 1998 standard and has also
> not changed in the current draft. I considered for a while that
> gcc might not view a temporary as an object, but this seems
> also rather clearly expressed in both 1.8 and 12.2.
> I observed that even my quite old mingw gcc 3.4, a rather old
> Borland Compiler (I just can't find its version number) and
> MS-VS2003 show the unexpected behaviour you mention.
> But no newer compiler I tested (including all public available
> Comeau online versions and MS-VS2005-SP1) did. Of course
> we have no majoritarian decision here, but I tend to say that
> the standard is unusually unmistakable here ;-)
The sentence you quoted is exceptionally clear. To discharge
the compiler vendors some, however: this could have been
mentionned in the the section on binding to a reference. If I
were writing a compiler, that's the section I'd be following in
detail when writing the relevant code, and I'd probably have
missed this one particular case as well.
> All newer compilers follow rather strict the mentioned rule:
> To enforce this, I simply added the operator FG(FG&) to your
> class and none (except the older ones) tried the conversion
> operator but gave up with something like "class "FG" has no
> suitable copy constructor".
> As a not very relevant sidenode: Even by using the language
> extension mode of MS-VS2005 the compiler did not do that
> but selected instead the actually forbidden FG(FG&) c'tor with
> a corresponding warning
> "nonstandard extension used : 'argument' : conversion from 'FG'
> to 'FG &' A non-const reference may only be bound to an lvalue;
> copy constructor takes a reference to non-const") warning).
A reasonable choice, given that earlier versions didn't even
warn when binding a temporary to a non-const reference. (Sun CC
uses the word "anachronism" for this sort of thing.)
> Concluding, I would say that a bug report for gcc seems a
> reasonable choice.
Sounds right to me. (To be fair, I should probably install the
latest version, and try it first. But unless there's already a
bug report on it, I'd be surprised if the behavior changed.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]