Consider this template:
template< typename T, typename RefT = T& >
class foo
{
typedef const RefT const_ref_t;
typedef const T& another_const_ref_t;
//...
};
I would assume that the types const_ref_t and another_const_ref_t would be equivalent. Both are const T&‘s. Yet they are not. Alas, the following demonstration of their not-equivalence is fairly elaborate. It hinges on using dynamic_cast<> to check the type of of another class.
class abstractBase
{
public: virtual ~abstractBase() {}
};
template< typename T >
class otherClass : public abstractBase
{
};
template< typename T, typename RefT = T& >
class foo
{
typedef const RefT const_ref_t;
typedef const T& another_const_ref_t;
public:
void discover( abstractBase* p )
{
otherClass< const_ref_t >* a =
dynamic_cast< otherClass< const_ref_t >* >( p );
otherClass< another_const_ref_t >* b =
dynamic_cast< otherClass< another_const_ref_t >* >( p );
assert( a ); // Fails
assert( b ); // Succeeds
}
};
void fn()
{
abstractBase* p = new otherClass< const int& >();
foo< int > f;
f.discover( p ); // Assertion on 'a' fails.
}
Sorry this is so complex, but it’s a simplified version of the situation where I discovered the question.
The question, then, is this. This code treats const int&, foo< int >::const_ref_t, and foo< int >::another_const_ref_t as equivalent, which seems reasonable given the typedefs. Yet dynamic_cast<> only treats foo< int >::another_const_ref_t as equivalent to const int&. It will return null in the other (foo< int >::const_ref_t) case.
Why?
Consider this:
Now
TRefis the same asFoo &, andTCRefis the same asconst Foo &.However,
const TRefis the same asconst (TRef) = const (Foo &), not(const Foo)&. But reference types are always constant, so the additionalconstdoesn’t add anything.If you prefer the comparison with pointers:
T&is essentially likeT * const, soTRef constis like(T * const) const, which just collapses toT * const.