Why is a const templated reference type different from a const reference type?
-
27-10-2019 - |
سؤال
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:
typedef Foo T;
typedef T & TRef;
typedef T const & TCRef;
Now TRef
is the same as Foo &
, and TCRef
is the same as const Foo &
.
However, const TRef
is the same as const (TRef) = const (Foo &)
, not (const Foo)&
. But reference types are always constant, so the additional const
doesn't add anything.
If you prefer the comparison with pointers: T&
is essentially like T * const
, so TRef const
is like (T * const) const
, which just collapses to T * const
.