Подтвердить что ты не робот

Каков тип decltype (this) в С++?

По-видимому, clang считает, что decltype(this) является указателем на класс cv-qual, а gcc считает, что это ссылка const на указатель на класс cv-qualified. GCC думает, что decltype(&*this) является указателем на класс cv. Это имеет некоторые последствия, когда оно используется в качестве имени шаблона для шаблона. Рассмотрим гипотетический пример:

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 { /* ... */ }; }
};

В этом примере один реализует пользовательский контейнер T. Являясь контейнером, он поддерживает итераторы. На самом деле два типа итераторов: iterator и const_iterator s. Было бы нецелесообразно дублировать код для этих двух, поэтому можно было бы написать класс итератора шаблона, взяв либо указатель на исходный класс MyContainer<T> *, либо указатель на версию const MyContainer<T> const *.

Когда cbegin и cend используются вместе, gcc ошибается, говоря, что он выводил конфликтующие типы, в то время как clang просто отлично работает.

4b9b3361

Ответ 1

Хорошо, вот что я нашел в стандарте (N3337), хотя:

7.1.6.2 Спецификаторы простого типа [dcl.type.simple]

4 Тип, обозначаемый decltype(e), определяется следующим образом:
  - если e - это unparenthesized id-expression или unparenthesized class member access (5.2.5), decltype(e) - это тип объекта, названного e. Если такой объект отсутствует или если eназывает набор перегруженных функций, программа плохо сформирована,
  - в противном случае, если e - значение x, decltype(e) - T&&, где T - тип e; - в противном случае, если e - значение l, decltype(e) - T&, где T - тип e; - в противном случае decltype(e) является типом e.
Операнд decltype specifier - неоцениваемый операнд (раздел 5).

и

5.1.1 Общие сведения [expr.prim.general]

3 Если декларация объявляет функцию-член или функцию-член шаблон класса X, выражение this является значением класса "указатель на cv-qualifier-seq X" между необязательным cv-qualifer-seqи конец функции-определения, member-declarator или <Я > описатель. Он не должен появляться перед необязательным cv-qualifier-seqи он не должен появляться в объявлении статического члена (хотя его тип и категория значений определены в пределах статическая функция-член, поскольку они находятся внутри нестатического элемента функция). [ Примечание: это потому, что совпадение объявлений не происходит пока не будет известен полный декларатор. - end note] В отличие от объекта выражение в других контекстах, *this не обязано быть полным тип для доступа к члену класса (5.2.5) вне члена функция корпус. [ Примечание: только участники класса, объявленные до декларация видна. - end note]

Предыдущая ссылка на §9.3.2 является ошибкой, так как это касается тела функции-члена, как указано ниже в комментарии от MWid.

9.3.2 Указатель `this` [class.this] 1 В теле нестатической (9.3) функции-члена ключевое слово `this` является выражением prvalue, значением которого является адрес объект, для которого вызывается функция. Тип `this` в член-функция класса `X` -` X * `. Если функция-член объявленный `const`, тип` this` является `const X *`, если член функция объявлена ​​`volatile`, тип` this` является `volatile X *`, и если функция-член объявлена ​​`const volatile`, тип `this` является` const volatile X * `.Дел >

Так выглядит gcc неправильно.

Ответ 2

this является prvalue, поэтому decltype(this) всегда должно быть простым X* (или X cv*/cv X*). Добавление const& кажется ошибкой в ​​GCC (проверено с g++ 4.8.1), которое происходит только для шаблона класса (не для "простого" класса) и только внутри возвращаемого типа возврата (не внутри тела функции-члена): демонстрация. Это, похоже, исправлено в GCC 4.9 (экспериментальный), вы можете протестировать здесь.