Type for the result of operator overloading for different ref-qualifiers

So, basically I am writing a template to determine the type of expression (in this case, the dereference operator):

template<class T>
struct Asgard {

  template <class T>
  static auto check(T) -> decltype(*std::declval<T>()); // <-- the important line

  static utils::tt::SubstFailure check(...);

  using Dereference = decltype(check(std::declval<T>()));

};

but after looking at an example on the net that has changed a bit ( here ):

template<class X>
static auto check(const X& x) -> decltype(x == x); // other operator, but not important.

this made me think about whether the operator is overloaded for different qualifiers of the object, so I created a test class:

struct ThorsChariot {
  std::integral_constant<int, 1> operator*() const &{
    return std::integral_constant<int, 1>();
  }
  std::integral_constant<int, 2> operator*() & {
    return std::integral_constant<int, 2>();
  }
  std::integral_constant<int, 3> operator*() const &&{
    return std::integral_constant<int, 3>();
  }
  std::integral_constant<int, 4> operator*() && {
    return std::integral_constant<int, 4>();
  }  
};

The following notation that I use basically means:

1 — the return type of a call onconst &
2                                  &
3                                  const &&
4                                  &&

And here is what I tested:

Asgard<const ThorsChariot>::Dereference
Asgard<ThorsChariot>::Dereference

Asgard<const ThorsChariot &>::Dereference
Asgard<ThorsChariot &>::Dereference

Asgard<const ThorsChariot &&>::Dereference
Asgard<ThorsChariot &&>::Dereference

I think that these types should be (in order) (I use nas a shortcut for integral_constant<int, n>(see note about recording above)):

1 2  1 2  3 4

And here are the results for different attempts:

(A)
static auto check(T) -> decltype(*std::declval<T>()); 
4 4  4 4  4 4

(B)
static auto check(T t) -> decltype(*t);
2 2  2 2  2 2

(C)
static auto check(const T &t) -> decltype(*t);
1 1  1 1  1 1

(D)
static auto check(T &&t) -> decltype(*t);
1 2  1 2  1 2

(E)
static auto check(T &&t) -> decltype(*std::forward<T>(t));
static auto check(T &&) -> decltype(*std::declval<T>());
3 4 1 2 3 4

(C) (D) . (A) (B) .
, , - (E). lvalue rvalue, rvalues. ? , ? ?

, , , , , , , , , .

+4
1

(E)
static auto check(T &&t) -> decltype(*std::forward<T>(t));

drop

Asgard<const ThorsChariot>::Dereference
Asgard<ThorsChariot>::Dereference

, ( , rvalue-). 1 2 3 4, .

, std::declval<T>() && T, rvalue, T lvalue, lvalue. std::forward<T>():

template< class T >
typename std::add_rvalue_reference<T>::type declval();

template< class T >
T&& forward( typename std::remove_reference<T>::type& t );

template< class T >
T&& forward( typename std::remove_reference<T>::type&& t );

, , . T Dereference check, std::declval<T>(), std::forward<T>():

template<class T>
struct Asgard {

  template <class T>
  static auto check(int) -> decltype(*std::declval<T>()); // <-- the important line

  template <class T>
  static utils::tt::SubstFailure check(...);

  using Dereference = decltype(check<T>(0));

};

( , int , ).

,

, , , . std::get, , , - ( , template). begin(), end() STL (), , , , .

const&&, , , , , . rvalue , ( , ). , , const&&, const& .

, volatile , , . .

+2

Source: https://habr.com/ru/post/1538828/


All Articles