Template metaprogramming with reference

I tested some cpp book template metaprogramming solutions for the first exercise http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?CPPTM_Answers_-_Exercise_2-0

Write a unary metafunction add_const_ref that returns T if it is a reference type and otherwise returns T const &

 template<typename T>
 struct add_const_ref
 {
     typedef typename boost::add_const<T>::type ct;
     typedef typename boost::add_reference<ct>::type type;
 };

      

I revisited it with C ++ 11:

 template<typename T>
 struct add_const_ref_type
 {
     typedef typename std::add_const<T>::type ct;
     typedef typename std::add_lvalue_reference<ct>::type type;
 };

      

I don't understand why it works with the link. I expect this to add const, i.e. Will change int&

to `const int &.

 int main()
 {   
    std::cout << std::is_same<add_const_ref_type<int &>::type, int&>::value << '\n'; // print 1
    std::cout << std::is_same<add_const_ref_type<int &>::type, const int&>::value << '\n'; // print 0

    return 0;
 }

      

+3


source to share


2 answers


You've been tricked into placing your type modifiers on the left.

const int&

      

I mean, it looks like when you apply const

to int&

, you are getting it const int&

right?

Wrong.

To understand what's going on here, apply the type modifiers on the right . The modifier always refers to the item to the right of it; at the moment, the claim that puts it "on the left" is illegal:

int const&

      

it is an int reference, which is a constant. This is really valid C ++.

int& const

      

it is absurd; you cannot apply const

to &

. &

themselves are already unchanged; only what they refer to can be changed.

When you are add_const<int&>

, you logically receive int& const

; the devil knows that this is nonsense, so it returns int&

.

Now we step back and see what happens if you place it on the left. If there is nothing on the left side, a special rule makes it apply to the leftmost one. So:

const int&

      

just



int const&

      

and

using X=int&;
const X

      

is an

X const

      

again, according to the rule "left to right of the leftmost part". After that, we expand X

:

int& const

      

It would be quite obvious that you always apply the type modifiers on the right and ignore the special case for the type modifiers on the left.


Fixing this, if you want to add const to value types and reference references to a const instance, it is easy to override it, but it is difficult to solve overall. After all, a link is a kind of alias, just like a pointer; when you add const

to a pointer you get a const pointer, not a const pointer.

I suspect the assignment allows you to solve the problem from scratch rather than using std

or boost

.

template<class T>
struct tag_t {using type=T;};
template<class T>
struct add_const_ref:tag_t<T>{};
template<class T>
struct add_const_ref<T&>:tag_t<T const&>{};

      

+6


source


This works because it int & const

doesn't make any sense (the reference is always const), so it is the std::add_const<int &>::type

same as int &

. That is, the part that is being executed const

is not int

.

Here's an example:



#include <iostream>
#include <type_traits>

int main() {
    std::cout << std::is_same<int &, std::add_const<int &>::type>::value << std::endl;
    std::cout << std::is_same<int, std::add_const<int>::type>::value << std::endl;
    std::cout << std::is_same<int const, std::add_const<int>::type>::value << std::endl;

    std::cout << std::is_same<int &, std::add_lvalue_reference<std::add_const<int &>::type>::type>::value << std::endl;
    std::cout << std::is_same<int &, std::add_lvalue_reference<std::add_const<int>::type>::type>::value << std::endl;
    std::cout << std::is_same<int const &, std::add_lvalue_reference<std::add_const<int>::type>::type>::value << std::endl;
}

      

Here online .

+3


source







All Articles