Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the type of decltype(this) in C++?

Apparently clang thinks decltype(this) is a pointer to the cv-qualified class, while gcc thinks it is a const reference to a pointer to the cv-qualified class. GCC only thinks decltype(&*this) is a pointer to the cv-qualified class. This has some implications when it is used as the typename for a template. Consider a hypothetical example:

template<typename T> class MyContainer {     /* ... */     template<typename ContainerPtr>     class MyIterator {         ContainerPtr container;         /* ... */     };     auto cbegin() const         -> MyIterator<decltype(&*this)> { return { /* ... */ }; }     auto cend() const         -> MyIterator<decltype(this)> { return { /* ... */ }; } }; 

In this example, one implements a custom container of T. Being a container, it supports iterators. In fact, two kinds of iterators: iterators and const_iterators. It would not make sense to duplicate the code for these two, so one could write a template iterator class, taking either a pointer to the original class MyContainer<T> * or a pointer to the const version MyContainer<T> const *.

When cbegin and cend are used together, gcc errors out, saying it deduced conflicting types, while clang just works fine.

like image 383
kccqzy Avatar asked Nov 16 '13 17:11

kccqzy


People also ask

What is the decltype of a function?

If the expression parameter is a call to a function or an overloaded operator function, decltype(expression) is the return type of the function. Parentheses around an overloaded operator are ignored. If the expression parameter is an rvalue, decltype(expression) is the type of expression.

What does decltype stand for?

Decltype keyword in C++ Decltype stands for declared type of an entity or the type of an expression. It lets you extract the type from the variable so decltype is sort of an operator that evaluates the type of passed expression. SYNTAX : decltype( expression )

What does decltype return?

decltype returnsIf what we pass to decltype is the name of a variable (e.g. decltype(x) above) or function or denotes a member of an object ( decltype x.i ), then the result is the type of whatever this refers to. As the example of decltype(y) above shows, this includes reference, const and volatile specifiers.

What does decltype auto do?

decltype(auto) is primarily useful for deducing the return type of forwarding functions and similar wrappers, where you want the type to exactly “track” some expression you're invoking.


2 Answers

this is a prvalue, so decltype(this) should always be plain X* (or X cv* / cv X*). The addition of const& seems to be a bug in GCC (tested with g++ 4.8.1), which happens only for a class template (not for a "plain" class) and only inside the trailing return type (not inside the body of the member function): demo. This seems to be fixed in GCC 4.9 (experimental), you can test here.

like image 77
gx_ Avatar answered Sep 19 '22 13:09

gx_


Okay, here is what I found in the standard (N3337) though:

7.1.6.2 Simple type specifiers [dcl.type.simple]

4   The type denoted by decltype(e) is defined as follows:
  — if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;
  — otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
  — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
  — otherwise, decltype(e) is the type of e.
The operand of the decltype specifier is an unevaluated operand (Clause 5).

and

5.1.1 General [expr.prim.general]

3   If a declaration declares a member function or member function template of a class X, the expression this is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifer-seq and the end of the function-definition, member-declarator, or declarator. It shall not appear before the optional cv-qualifier-seq and it shall not appear within the declaration of a static member function (although its type and value category are defined within a static member function as they are within a non-static member function).   [ Note: this is because declaration matching does not occur until the complete declarator is known. — end note ] Unlike the object expression in other contexts, *this is not required to be of complete type for purposes of class member access (5.2.5) outside the member function body. [ Note: only class members declared prior to the declaration are visible. — end note ]

The previous reference to §9.3.2 is an error, since that deals with the body of a member function, as pointed out below in a comment by MWid.

9.3.2 The `this` pointer [class.this] 1   In the body of a non-static (9.3) member function, the keyword `this` is a prvalue expression whose value is the address of the object for which the function is called. The type of `this` in a member function of a class `X` is `X*`. If the member function is declared `const`, the type of `this` is `const X*`, if the member function is declared `volatile`, the type of `this` is `volatile X*`, and if the member function is declared `const volatile`, the type of `this` is `const volatile X*`.

So it looks like gcc is wrong.

like image 21
kccqzy Avatar answered Sep 16 '22 13:09

kccqzy