According with [5/8] and [7.1.7.2/4] (working draft):
decltype
specifier is an unevaluated operand
Consider the code below:
#include<type_traits>
struct S { using type = int; };
int f(int i);
template<typename T>
typename T::type g(T);
template<typename T>
auto h(T v) { return v; }
int main() {
static_assert(std::is_same<decltype(f(42)), int>::value, "!");
static_assert(std::is_same<decltype(g(S{})), int>::value, "!");
static_assert(std::is_same<decltype(h(42)), int>::value, "!");
}
It goes without saying that f
and g
are not evaluated actually.
On the other side, the function h
has an auto
return type that is deduced from its body, thus from its arguments and thus from the deduced type T
.
Can it still be considered an unevaluated operand in this case?
I mean, it seems to me that, in the context of the decltype
, the function h
must be evaluated to know what the actual return type is.
For I'm quite sure that the working draft is right, the question is: what's wrong in my reasoning?
In order to determine the type denoted by decltype(h(42))
, the compiler needs to perform template argument deduction for h
and instantiate the template specialization h<int>
to examine its body and determine the return type. This is not the same as evaluating h(42)
; for example, if h
contained any side effects such as printing a message, those side effects would not occur.
Can it still be considered an unevaluated operand in this case? I mean, it seems to me that, in the context of the decltype, the function h must be evaluated to know what the actual return type is.
It's still an Unevaluated context. As Brain's answer(which is the shorter answer) explains.
The C++ standard talks about template argument deduction process, and in substituting arguments for function templates: [temp.deduct/7] (emphasis mine):
The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside
sizeof
,decltype
, and other contexts that allow non-constant expressions. The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered.
You can start reading from the first paragraph to get more detailed info about template argument deduction.
(Note: All quoted paragraphs are partially reproduced, click the section links to see the full paragraph):
Since you already know about decltype
and unevaluated contexts, and have quoted relevant sections, we can skip those and start with auto
...
[dcl.spec.auto/1]: The
auto
anddecltype(auto)
type-specifiers are used to designate a placeholder type that will be replaced later by deduction from an initializer....
A view from placeholder types:
[dcl.spec.auto/2]: The placeholder type can appear with a function declarator... ... If the declared return type of the function contains a placeholder type, the return type of the function is deduced from non-discarded
return
statements, if any, in the body of the function
About placeholder type deduction:
[dcl.type.auto.deduct/1]: Placeholder type deduction is the process by which a type containing a placeholder type is replaced by a deduced type.
Deducing placeholder return types:
[type.auto.deduct/4]: If the placeholder is the auto type-specifier, the deduced type
T'
replacingT
is determined using the rules for template argument deduction
If the story isn't very clear, you may want to read the entire sections for each quoted paragraph.
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