
Hello, I am going through the book C++ Template Metaprogramming and wanted a sanity check on Exercise 2-0 from the book. My first question is: What would be a motivating example for why one would want a add_const_ref<T> metafunction that returned T if it was a reference and T const& otherwise? My second question is: How did I do? My guess is that the second crack is more correct. Here is crack one: My first crack at the exercise is below (my 2nd crack is below that) #include <iostream> #include <boost/type_traits/is_reference.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/static_assert.hpp> using namespace std; template<typename T, bool> struct add_const_ref { typedef T const& value_type; }; template<typename T> struct add_const_ref<T, true> { typedef T value_type; }; template<typename T> void func(typename add_const_ref<T, boost::is_reference<T>::value
::value_type t)
{ // .. do something } class BigClass { }; int main() { int i = 0; BOOST_STATIC_ASSERT((boost::is_same<add_const_ref<int&, boost::is_reference<int&>::value >::value_type, int&>::value)); BOOST_STATIC_ASSERT((boost::is_same<add_const_ref<int, boost::is_reference<int>::value >::value_type, int const&>::value)); func<int&>(i); BigClass myBigClass; func<BigClass>(myBigClass); return 0; } After taking a look at add_reference.hpp in boost I modified my answer to the one below: #include <iostream> #include <boost/type_traits/is_reference.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/static_assert.hpp> using namespace std; template<bool> struct const_ref_adder { template<typename T> struct result_ { typedef T const& value_type; }; }; template<> struct const_ref_adder<true> { template<typename T> struct result_ { typedef T value_type; }; }; template<typename T> struct add_const_ref { typedef typename const_ref_adder<boost::is_reference<T>::value
::template result_<T>::value_type value_type;
}; template<typename T> void func(typename add_const_ref<T>::value_type t) { // .. do something } class BigClass { }; int main() { int i = 0; BOOST_STATIC_ASSERT((boost::is_same<add_const_ref<int&>::value_type, int&>::value)); BOOST_STATIC_ASSERT((boost::is_same<add_const_ref<int>::value_type, int const&>::value)); func<int&>(i); BigClass myBigClass; func<BigClass>(myBigClass); return 0; } Thanks in advance for your input, Bruce

Trask, Bruce (US SSA) wrote:
It's useful for forwarding function arguments. This document gives several examples of cases where one may want to do that: <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm>. Forwarding must be done by reference, but implementations are required to treat T & as ill-formed if T is a reference type, rather than treating it as being the same as T. add_const_ref<T> should yield the correct type to use for forwarding an argument of type T.
Well the first attempt doesn't solve the problem because it requires an extra parameter. The second attempt solves it but I don't think you're supposed to make use of other templates. I think the expected solution would be more like this: template<typename T> struct add_const_ref { typename T const & type; }; template<typename T> struct add_const_ref<T &> { typename T & type; }; Ben.

Ben Hutchings wrote:
Any solutions is allowable, though that one is not particularly elegant.
Actually there's a much more concise solution using the type traits library. That is, after all, the focus of the chapter. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (3)
-
Ben Hutchings
-
David Abrahams
-
Trask, Bruce (US SSA)