metaprogramming exercise 2-0
I just finished the first exercise in the C++ meta programming book. Then I checked what had been done before on this mailing list. Here is my solution: using namespace boost; template <bool use_ref, typename T> struct add_const_ref_impl { typedef T const & type; }; template <typename T> struct add_const_ref_impl<true, T> { typedef T type; }; template<class T> struct add_const_ref { typedef typename add_const_ref_impl<is_reference<T>::value, T>::type type; }; From Bruce Trask comes: using namespace boost; template<typename T> struct add_const_ref { typedef typename add_reference<typename add_const<T>::type>::type type; }; His solution is SO much better then mine. However, when I first saw it I thought it must be wrong because I assumed that add_const on a reference would would return a const reference. In other words, the code below would be false: bool a = is_same<add_const<int &>::type, int &>::value; However! bool "a" is true. So my question is why is "a" true? Why isn't add_const<int &>::type == int const &? Thanks, Chris
Chris Goller <cgoller@magpiesystems.com> writes:
His solution is SO much better then mine.
You can do even better (hint: you don't need to use add_const).
However, when I first saw it I thought it must be wrong because I assumed that add_const on a reference would would return a const reference. In other words, the code below would be false:
bool a = is_same<add_const<int &>::type, int &>::value;
However! bool "a" is true. So my question is why is "a" true? Why isn't add_const<int &>::type == int const &?
It's not a very interesting answer: that's just the way the C++ type system works. The rule is, essentially, that add_const<T>::type is equivalent to T const. When you do that with int&, you get int& const Think of that as being like int* const The int isn't const, here; the pointer is. But unlike pointers, references can't be made to refer to new things. So int& const and int& are really the same type. Both are different from int const& where the int is immutable through that reference. HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com
David- First, thanks for the response. BTW, I really like the book. Okay, I understand what you are saying about add_const and how it works. My next question is why was it implemented in that way? In other words, was there a specific reason not to make a special case for references such that add_const<int&> would be int const &? As for the better solution, I'll keep working on it! Chris David Abrahams wrote:
Chris Goller <cgoller@magpiesystems.com> writes:
His solution is SO much better then mine.
You can do even better (hint: you don't need to use add_const).
However, when I first saw it I thought it must be wrong because I assumed that add_const on a reference would would return a const reference. In other words, the code below would be false:
bool a = is_same<add_const<int &>::type, int &>::value;
However! bool "a" is true. So my question is why is "a" true? Why isn't add_const<int &>::type == int const &?
It's not a very interesting answer: that's just the way the C++ type system works.
The rule is, essentially, that
add_const<T>::type
is equivalent to
T const.
When you do that with int&, you get
int& const
Think of that as being like
int* const
The int isn't const, here; the pointer is. But unlike pointers, references can't be made to refer to new things. So
int& const
and
int&
are really the same type. Both are different from
int const&
where the int is immutable through that reference.
HTH,
Chris Goller wrote:
David-
First, thanks for the response. BTW, I really like the book.
Okay, I understand what you are saying about add_const and how it works.
My next question is why was it implemented in that way? In other words, was there a specific reason not to make a special case for references such that add_const<int&> would be int const &?
FWIW, you will soon be able to get that effect without a metafunction. from http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#106 [example] int i; typedef int& RI; RI& r = i; // r has the type int& const RI& r = i; // r has the type const int& [/example] I'm not sure I like it, because a 'RI const' is 'int&', but a reference to a 'RI const' is 'int const&'. But maybe its useful that way. Cheers, Ian McCulloch
Ian McCulloch <ianmcc@physik.rwth-aachen.de> writes:
Chris Goller wrote:
David-
First, thanks for the response. BTW, I really like the book.
Okay, I understand what you are saying about add_const and how it works.
My next question is why was it implemented in that way? In other words, was there a specific reason not to make a special case for references such that add_const<int&> would be int const &?
FWIW, you will soon be able to get that effect without a metafunction. from http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#106 [example] int i; typedef int& RI; RI& r = i; // r has the type int& const RI& r = i; // r has the type const int& [/example]
I'm not sure I like it, because a 'RI const' is 'int&', but a reference to a 'RI const' is 'int const&'. But maybe its useful that way.
Oh, that's very disturbing. What is the rationale for moving the const inside the reference? Ah, I see it in N1245: template<class T> class X { f(const T&) ; /* ... */ }; X<int&> x; // X<int&>::f has the argument type const int& I'm not convinced that special rule is worth the breath and text needed to explain it. With any well-behaved class X, if f was written to work on a "const X&" argument, it will work equally well and correctly on a "X&" argument. It's probably too late for objections now, though. -- Dave Abrahams Boost Consulting www.boost-consulting.com
FWIW, you will soon be able to get that effect without a metafunction. from http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#106 [example] int i; typedef int& RI; RI& r = i; // r has the type int& const RI& r = i; // r has the type const int& [/example]
I'm not sure I like it, because a 'RI const' is 'int&', but a reference to a 'RI const' is 'int const&'. But maybe its useful that way.
Oh, that's very disturbing. What is the rationale for moving the const inside the reference?
Ah, I see it in N1245:
template<class T> class X { f(const T&) ; /* ... */ };
X<int&> x; // X<int&>::f has the argument type const int&
I'm not convinced that special rule is worth the breath and text needed to explain it. With any well-behaved class X, if f was written to work on a "const X&" argument, it will work equally well and correctly on a "X&" argument.
It's probably too late for objections now, though.
I don't think this affects add_const as such: Adding a const qualifier to a reference type still has no effect, it's only when you add a reference qualifier to a reference type that the cv-qualifiers get combined in this way. Assuming I've understood correctly of course! John.
Chris Goller <cgoller@magpiesystems.com> writes:
David-
First, thanks for the response. BTW, I really like the book.
Thank you; I'll make sure that Aleksey knows.
Okay, I understand what you are saying about add_const and how it works.
My next question is why was it implemented in that way? In other words, was there a specific reason not to make a special case for references such that add_const<int&> would be int const &?
I can't speak for the designer (John Maddock, I think), but: 1. in general special cases are best avoided. They make interfaces harder to explain and use. 2. In this case there's no obvious advantage to making a special case. 3. The type traits library is basically designed to reflect the standard's definitions and rules. That would be a gratuitous deviation. -- Dave Abrahams Boost Consulting www.boost-consulting.com
However, when I first saw it I thought it must be wrong because I assumed that add_const on a reference would would return a const reference. In other words, the code below would be false:
bool a = is_same<add_const<int &>::type, int &>::value;
However! bool "a" is true. So my question is why is "a" true? Why isn't add_const<int &>::type == int const &?
I thought the same thing at first but it makes senses when we compare a reference to a constant pointer. add_const<int * const>::type would be int * const and not int const * const. You might also try the following : template <typename T> struct AC { typedef const T type; }; and then check the result of is_same<AC<int &>, int&>::value. Under Visual C++ with default compilation setting AC struct will give a compilation warning when template argument is a reference : warning C4181: qualifier applied to reference type; ignored
Thanks,
Chris
Philippe
participants (5)
-
Chris Goller
-
David Abrahams
-
Ian McCulloch
-
John Maddock
-
Philippe Mori