Почему в реализации функции-члена тип результата не может быть описан с помощью определения в классе?

Реорганизовав некоторый код, я обнаружил, что если у меня есть определение функции-члена вне класса, его возвращаемый тип не может использовать имена, определенные с помощью "using" внутри этого класса.

#include <iostream>

class Foo {
public:
    using Bar = int;
    Bar f();
};

Bar Foo::f() {
    return 42;
}

int main() {
    std::cout << Foo().f();
    return 0;
}

Этот код не будет компилироваться с ошибкой: "Bar" не называет тип. Я все еще могу использовать:

Foo::Bar Foo::f() {
    return 42;
}

но с длинными именами это выглядит намного хуже.

Каковы причины этого? Почему я могу просто использовать Bar в качестве типа параметра, но должен добавить Foo::, чтобы использовать его в качестве возвращаемого типа?

2 ответа

Причина в том, где функция определена, что Bar не входит в сферу. Это на самом деле Foo::Barи это не кандидат на совпадение с неквалифицированным именем Bar вне определения класса.

Так что измените определение на

Foo::Bar Foo::f()
{
    return 42;
}

Если вы хотите быть действительно ясными в пользу простых смертных, которые видят только заголовок, содержащий определение класса, также измените объявление функции (в определении класса) таким же образом.

Вы пытаетесь использовать использование Bar в качестве возвращаемого типа, но этот тип не определен в вашей области видимости. Рассмотрите возможность использования typedef лайк

#include <iostream>

typedef int Bar;
class Foo {
public:
    Bar f();
};

Bar Foo::f() {
    return 42;
}

int main() {
    std::cout << Foo().f();
    return 0;
}

РЕДАКТИРОВАТЬ: выяснить, почему ваш текущий код не работает без FOO:: (согласно предложению пользователя @swordfish) В вашем примере вы используете using ключевое слово для объявления псевдонима типа внутри class Foo, Эта функция была добавлена ​​в C++ 11. Когда вы пытаетесь определить функцию класса вне класса, это using внутри класса не видно, и поэтому вы должны предварять FOO:: чтобы это работало. это похоже на typedef, но typedef использование не будет идеальным, если вы хотите объявить класс Baz в том же пространстве имен, которое выглядит так

class Baz {
public:
    using Bar = double;
    Bar f();
};
Baz::Bar Baz::f() {
    return 42.1234;
}
Другие вопросы по тегам