std::declval(3)
π
std::declval(3) π
okay so bestie, this is the std::declval page from the C++ Standard Libary manual β yes, thatβs how the manual name is spelled up top, and weβre keeping it π. Buckle up, because this tiny function is lowkey iconic in template-land.
π NAME π
std::declval β std::declval
likeβ¦ thatβs literally the NAME line, bestie. No extra lore, just the name twice with a dash in the middle π«Ά.
β¨ Synopsis β¨
Defined in header <utility>
template< class T >
(since C++11)
typename std::add_rvalue_reference<T>::type declval() noexcept;
So this thing converts any type T to a reference type, making it possible to use member functions in the operand of the decltype specifier without the need to go through constructors. Thatβs the whole slay.
std::declval is commonly used in templates where acceptable template parameters may have no constructor in common, but have the same member function whose return type is needed. iykyk.
β οΈ bestie, read this part twice: note that std::declval can only be used in unevaluated contexts and is not required to be defined; it is an error to evaluate an expression that contains this function. Formally, the program is ill-formed if this function is odr-used. not me warning you dramatically, but also yes π.
π Parameters π
(none) β literally no parameters. zero. nada. the void is empty and itβs giving minimalist queen π«Ά.
π¦ Return value π¦
Cannot be called and thus never returns a value. periodt.
The return type is T&& unless T is (possibly cv-qualified) void, in which case the return type is T. cute, right?
π§ Possible implementation π§
template<typename T>
typename std::add_rvalue_reference<T>::type declval() noexcept
{
static_assert(false, "declval not allowed in an evaluated context");
}
this is the possible implementation and the static_assert is sitting there like a little bouncer at the club, bestie πͺβ¨.
πΈ Example πΈ
// Run this code
#include <iostream>
#include <utility>
struct Default
{
int foo() const { return 1; }
};
struct NonDefault
{
NonDefault() = delete;
int foo() const { return 1; }
};
int main()
{
decltype(Default().foo()) n1 = 1; // type of n1 is int
// decltype(NonDefault().foo()) n2 = n1; // error: no default constructor
decltype(std::declval<NonDefault>().foo()) n2 = n1; // type of n2 is int
std::cout << "n1 = " << n1 << '\n'
<< "n2 = " << n2 << '\n';
}
the commented-out line is the vibe check failing, and the std::declval line is the main character fixing it π
.
π Output π
n1 = 1
n2 = 1
ate. no crumbs. π₯
π See also π
decltype specifier(C++11)β obtains the type of an expression or an entityresult_of(C++11)(removed in C++20)(class template)β deduces the result type of invoking a callable object with a set of argumentsinvoke_result(C++17)(class template)β deduces the result type of invoking a callable object with a set of arguments
source/version + date, bestie: http://cppreference.com Β· 2024.06.10 Β· page std::declval(3) β mwah πβ¨
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms