implicit_cast isn't possible... is it?

T

Tomás

Given the following:

static_cast<T>( expr )


This will evaluate to an l-value if T is a reference type -- otherwise it
will evaluate to an r-value.
The same goes for reinterpret_cast.

I've been trying to write an "implicit_cast", but I don't think it's
possible to achieve the same behaviour.

For instance, here would be its most basic use:

/* Code Snippet A */

void SomeFunc( signed char ) {}
void SomeFunc( unsigned char ) {}

int main()
{
SomeFunc( implicit_cast<unsigned char>(45) );
}


But then if we simulatenously try to achieve the l-value behaviour, it
won't compile -- giving an ambiguity error. Here's the code I have so
far:

/* Code Snippet B */


template <class U, class T>
inline U implicit_cast(const T& t) { return t; }

template <class U, class T>
inline U implicit_cast(T& t) { return t; }


void SomeFunc(unsigned char) {}
void SomeFunc(signed char) {}


struct Base {

void SomeConstFunction() const {}

};

struct Derived : Base { Derived() {} };


int main()
{
SomeFunc( implicit_cast<unsigned char>(27) );

SomeFunc( implicit_cast<signed char>(27) );


Derived derived;

implicit_cast<Base&>(derived) = Base();


Derived const cderived;

implicit_cast<const Base&>(cderived).SomeConstFunction();

/* The line immediately above results in an ambiguity error */
}


(Initially I thought we'd have the problem of "implicit_cast" creating a
temporary object when its U parameter is a non-reference type, but this
doesn't seem to be a problem because "static_cast" does the same thing,
e.g.:)

/* Code Snippet C */

#include <iostream>
using std::cout;

#include <cstdlib>

struct Base {

void PrintMyAddress() const
{
cout << static_cast<const void*>(this);

/* Here's an instance where I'd use
implicit_cast */
}

};

struct Derived : Base {};

int main()
{
Derived derived;

static_cast<Base>(derived).PrintMyAddress();

cout << '\n';

static_cast<Base&>(derived).PrintMyAddress();

cout << '\n';

std::system("PAUSE");
}


Any ideas for resolving the ambiguity error in code snippet B?


-Tomás
 
T

Tomás

I've been trying to find a solution for this but haven't come up with
anything. Here's the closest I've gotten:

template <class U, class T>
inline U implicit_cast(const T& expr)
{
return static_cast<T&>(expr);
}


The problem though is that if "t" refers to an object which is actually
const, then "T" is STILL a non-const type. If "T" retained its constness,
such that the following defined a local const variable within the function:

T obj;

then the above code snippet would work as desired. But alas, it doesn't.


Of course my first attempt was:

template <class U, class T>
inline U implicit_cast(const T& expr)
{
return expr;
}

template <class U, class T>
inline U implicit_cast(T& expr)
{
return expr;
}


but that resulted in ambiguity errors. I'm getting ambiguity errors for the
code snippet immediately above, but why DON'T I get ambiguity errors for
the following:

template<class T>
void Func ( const T& obj ) {}

template<class T>
void Func ( T& obj ) {}

int main()
{
int n = 5;

int const cn = 5;

Func(n);

Func(cn);

Func(5);
}


At first glance, it looks like a compiler bug -- I'm getting ambiguity
errors for "implicit_cast" simply because it has two template parameters
rather than one, which just doesn't make sense.

-Tomás
 
V

Victor Bazarov

Tomás said:
I've been trying to find a solution for this but haven't come up with
anything. Here's the closest I've gotten:

template <class U, class T>
inline U implicit_cast(const T& expr)
{
return static_cast<T&>(expr);
}

[...]

Just wanted to ask (without doing much thinking yet)... Is there any
reason you wanted to use the reference argument instead of just 'T'?

V
 
A

Alf P. Steinbach

* Tomás:
Given the following:

static_cast<T>( expr )


This will evaluate to an l-value if T is a reference type -- otherwise it
will evaluate to an r-value.
The same goes for reinterpret_cast.

I've been trying to write an "implicit_cast", but I don't think it's
possible to achieve the same behaviour.

For instance, here would be its most basic use:

/* Code Snippet A */

void SomeFunc( signed char ) {}
void SomeFunc( unsigned char ) {}

int main()
{
SomeFunc( implicit_cast<unsigned char>(45) );
}


But then if we simulatenously try to achieve the l-value behaviour, it
won't compile -- giving an ambiguity error. Here's the code I have so
far:

/* Code Snippet B */


template <class U, class T>
inline U implicit_cast(const T& t) { return t; }

template <class U, class T>
inline U implicit_cast(T& t) { return t; }


void SomeFunc(unsigned char) {}
void SomeFunc(signed char) {}


struct Base {

void SomeConstFunction() const {}

};

struct Derived : Base { Derived() {} };


int main()
{
SomeFunc( implicit_cast<unsigned char>(27) );

SomeFunc( implicit_cast<signed char>(27) );


Derived derived;

implicit_cast<Base&>(derived) = Base();


Derived const cderived;

implicit_cast<const Base&>(cderived).SomeConstFunction();

/* The line immediately above results in an ambiguity error */
}


(Initially I thought we'd have the problem of "implicit_cast" creating a
temporary object when its U parameter is a non-reference type, but this
doesn't seem to be a problem because "static_cast" does the same thing,
e.g.:)

/* Code Snippet C */

#include <iostream>
using std::cout;

#include <cstdlib>

struct Base {

void PrintMyAddress() const
{
cout << static_cast<const void*>(this);

/* Here's an instance where I'd use
implicit_cast */
}

};

struct Derived : Base {};

int main()
{
Derived derived;

static_cast<Base>(derived).PrintMyAddress();

cout << '\n';

static_cast<Base&>(derived).PrintMyAddress();

cout << '\n';

std::system("PAUSE");
}


Any ideas for resolving the ambiguity error in code snippet B?

First, that given 'Derived derived', the compiler is free to choose T =
'Derived' or 'T = Derived const'. Even if the latter would yield a
compilation error (as long as that error isn't covered by SFINAE rules).
And I think this is what's giving you an ambiguity problem.

So you'd want to enforce the same const'ness for types U and T, e.g.,
instead of specifying the argument type as T, specifying it like
'typename ConstVersion<T, IsConst<U>::yes>::Type&'.

Here's an example of detecting constness, not tested:

template< class T >
struct IsConst
{
static T& aT();
static SizeNFalse isConstArg( T& );
static SizeNTrue isConstArg( T const& );

enum{ yes = sizeof( isConstArg( aT() ) ) == sizeof( SizeNTrue ) };
};
 
T

Tomás

Victor Bazarov posted:

template <class U, class T>
inline U implicit_cast(const T& expr)
{
return static_cast<T&>(expr);
}

[...]

Just wanted to ask (without doing much thinking yet)... Is there any
reason you wanted to use the reference argument instead of just 'T'?


Implicit downcast from derived to base, and still retain L-value-ness:


implicit_cast<Base&>(derived_object).SomeMethod();


-Tomás
 
A

Alf P. Steinbach

* Alf P. Steinbach:
Here's an example of detecting constness, not tested:

template< class T >
struct IsConst
{
static T& aT();
static SizeNFalse isConstArg( T& );
static SizeNTrue isConstArg( T const& );

enum{ yes = sizeof( isConstArg( aT() ) ) == sizeof( SizeNTrue ) };
};

Uh, those args need to pointers, not references, in case no copy
constructor is available in T. Ditto for result of aT().
 
R

red floyd

Alf said:
* Alf P. Steinbach:

Uh, those args need to pointers, not references, in case no copy
constructor is available in T. Ditto for result of aT().

Why? You're never passing anything by value. You're passing and
returning T's by reference only, so no copy constructor is invoked on a T.
 
T

Tomás

To put things into perspective, here's a code snippet which uses
"static_cast". I want to replace all instances of static_cast with
implicit_cast, and to have it behave identically:

void SomeFunc( unsigned char ) {}
void SomeFunc( signed char ) {}

class Base {
public:

Base() {}

void SomeConstFunction() const {}

void SomeNonConstFunction() {}

};

class Derived : public Base
{
public:

Derived() {}

};


int main()
{
/* First we'll work with simple POD literals: */

SomeFunc( static_cast<unsigned char>(76) );
SomeFunc( static_cast<signed char>(76) );


/* Now we'll deal with L-value-ness */

Derived derived;

static_cast<Base&>(derived) = Base(); /* Just to demonstrate
L-valueness */


static_cast<Base&>(derived).SomeNonConstFunction();


static_cast<const Base&>(derived).SomeConstFunction();



Derived const c_der;

static_cast<const Base&>(c_der).SomeConstFunction();


// static_cast<Base&>(c_der); /* ERROR: Won't compile */

}


I presently have sample code which satisfies all the above requirements,
except that it DOESN'T result in a compile error if you try to compile
the last line of code I wrote above. Here it is:

template<class U, class T>
inline U implicit_cast( const T& expr )
{
return const_cast<T&>(expr);
}


-Tomás
 
T

Tomás

Here's my latest attempt (but still doesn't compile):


template<class T>
struct Wrapper {

typedef T TypeCV;

TypeCV &stored;

Wrapper( TypeCV &arg ) : stored(arg) {}

operator TypeCV&()
{
return stored;
}

};

template<class U, class T>
inline U implicit_cast( Wrapper<T> expr )
{
typedef typename Wrapper<T>::TypeCV TypeCV;

return static_cast<TypeCV&>(expr);
}


/* Here comes the code which has had "static_cast" replaced
with "implicit_cast". */


void SomeFunc( unsigned char ) {}
void SomeFunc( signed char ) {}

class Base {
public:

Base() {}

void SomeConstFunction() const {}

void SomeNonConstFunction() {}

};

class Derived : public Base
{
public:

Derived() {}

};


int main()
{
SomeFunc( implicit_cast<unsigned char>(76) );
SomeFunc( implicit_cast<signed char>(76) );


Derived derived;


implicit_cast<Base&>(derived) = Base(); /* Just to demonstrate
L-valueness */

implicit_cast<Base&>(derived).SomeNonConstFunction();


implicit_cast<const Base&>(derived).SomeConstFunction();



Derived const c_der;

implicit_cast<const Base&>(c_der).SomeConstFunction();


// implicit_cast<Base&>(c_der); /* ERROR: Won't compile */

}


-Tomás
 

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,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top