Decltype как возвращаемый тип в функции члена класса

Я получил компиляцию ошибок ниже кода.

struct B{
    double operator()(){
        return 1.0;
    }
};

struct A {
    auto func() -> decltype(b())
    {
        return b();
    }

    B b;
};

Однако, если я реорганизую A, он компилируется.

gcc 4.8 сказал, что 'b' не был объявлен в этой области.

struct A {
    B b;
    auto func() -> decltype(b())
    {
        return b();
    }
};

Итак, что не так с первым?

Ответ 1

Определение class обрабатывается двумя проходами: сначала собираются объявления участников, включая сигнатуры функций, а затем анализируются тела определений.

Таким образом, тело функции имеет доступ ко всем объявлениям участников, включая последующие, но прототип функции видит только предшествующие объявления.

Ответ 2

Действительно ли это?

Ваш последний пример хорошо сформирован, а первый - нет (так что GCC правильно).

Параграф 3.4.1/7 о неквалифицированном поиске имен указывает:

Имя, используемое в определении класса X вне тела функции-члена, аргумент по умолчанию, скобка-или- равный-инициализатор нестатического элемента данных или определение вложенного класса должно быть объявлено в одном из следующие способы:

- перед его использованием в классе X или быть членом базового класса X (10.2) или

- [...]

И что следует за другими условиями, которые не применяются в вашем случае.

Ответ 3

Вы также можете заставить его работать следующим образом:

struct B
{
    double operator()()
    {
        return 1.0;
    }
};

// my implementation does not have std::declval
template < typename T > T&& declval();

struct A
{
    B b;
    auto func() -> decltype(declval<B>().operator()())
    {
        return b();
    }
};

изменить: или поскольку B в области видимости уже в любом случае не нуждается в auto, → decltype и declval

struct A
{
    B b;
    decltype(Q()()) func()
    {
        return b();
    }
};