The following code is excerpted from cppreference.com.
#include <iostream>
#include <type_traits>
struct foo
{
void m() { std::cout << "Non-cv\n"; }
void m() const { std::cout << "Const\n"; }
};
template <class T>
void call_m()
{
T().m();
}
int main()
{
call_m<foo>();
call_m<std::add_const<foo>::type>();
}
However, when compiled with VC++ Nov 2012 CTP, the output is
Non-cv
Non-cv
rather than the expected:
Non-cv
Const
Besides, what's the difference between the following two statements:
call_m<const foo>();
and
call_m<std::add_const<foo>::type>();
This appears to be a bug with MSVC. Using an expression of the form T()
(which is an explicit type conversion, as far as the standard is concerned) results in a prvalue of the specified type.
The expression
T()
, whereT
is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified)void
type, creates a prvalue of the specified type, which is value-initialized
It is only with non-class types that the const
would be ignored, due to a rule that non-class prvalues cannot have cv-qualified types:
Class prvalues can have cv-qualified types; non-class prvalues always have cv-unqualified types.
So the temporary object created by T()
here should be const
and should therefore call the const
member function.
As for when and why you would use std::add_const
, we can take a look at the reason it was included in the proposal. It states that the add_const
, add_volatile
, add_cv
, add_pointer
, and add_reference
type traits were removed from the proposal but then reinstated after complaints from users of Boost.
The rationale is that these templates are all used as compile time functors which transform one type to another [...]
The example given is:
// transforms 'tuple<T1,T2,..,Tn>'
// to 'tuple<T1 const&,T2 const&,..,Tn const&>'
template< typename Tuple >
struct tuple_of_refs
{
// transform tuple element types
typedef typename mpl::transform<
typename Tuple::elements,
add_reference< add_const<_1> > // here!
>::type refs;
typedef typename tuple_from_sequence<refs>::type type;
};
template< typename Tuple >
typename tuple_of_refs<Tuple>::type
tuple_ref(Tuple const& t)
{
return typename tuple_of_refs<Tuple>::type(t);
}
You can think of mpl::transform
as taking the compile-time metaprogramming equivalent to a function pointer as its second template argument - add_reference<add_const<...>>
is applied to each of the types in Tuple::elements
. This simply couldn't be expressed using const
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With