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>());
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);
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 on — const &
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. ?
, ? ?
, , , , , , , , , .