I wanted to try writing a template wrapper that checks whether a class has a member function. and for this it was necessary to use std::declval
template<typename T>
struct has_member<T, void_t<decltype(std::declval<T>().push_back())>>:std::true_type{};
As I saw, the implementation of declval should be like this:
template<typename T>
T&& declval() noexcept;
And actually, it may be a odd question ,but why does declval have no return statement ?
If I understand correctly, it should return rvalue to the place of its call:
template<typename T>
struct has_member<T, void_t<decltype(T&&.push_back())>>:std::true_type{};
But we don't use return in the implementation . Maybe it's because we don't have a function body?I would like to understand why this is possible. I would be happy to help
declval has no return statement because the function has no implementation. If you ever tried to call declval, you would get a compile error.
declval exists to be used in what C++ calls an "unevaluated context". This is in a place where an expression will be parsed, the types used worked out, but the expression will never actually be evaluated. The expression given to decltype is an unevaluated context.
Even though declval has no implementation, it is a function with a well-defined return type. So even though you can't actually execute it, the compiler does know what the type of declval<T>() will be. And therefore, the compiler can examine the expression containing it.
See, T&& is a type; you cannot use . on a type. The result of calling a function is an object (or void), which has a type, but isn't itself a type. What you want to say is "assuming I have a value of type T, I want to do X to it". You can't say that with T&& because it's a type, not an object. And you don't want to limit T to things which are default constructible, so you can't just say T{}.
That's where declval comes in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With