Why in member function implementation result type can't be described by using defined in class?

8.5k Views Asked by At

Refactoring some code, I found, that if I have member function definition outside of the class, it's return type can't use names defined by "using" inside this class.

#include <iostream>

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

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

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

This code won't compile, with error: ‘Bar’ does not name a type. I can still use:

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

but with long names it looks much worse.

What are the reasons behind this? Why can I simply use Bar as a parameter type, but has to add Foo:: to use it as a return type?

2

There are 2 best solutions below

0
On BEST ANSWER

The reason is, where the function is defined, that Bar is not in scope. It is actually Foo::Bar, and that is not a candidate for matching an unqualified name Bar outside the class definition.

So change the definition to

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

If you want to be really clear for the benefit of mere mortals who only have visibility of the header containing the class definition, also change the declaration of the function (within the class definition) in the same way.

1
On

You are trying to use use Bar as a return type, but this type is not defined in your scope. Consider using a typedef like

#include <iostream>

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

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

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

EDIT: elaborating why your current code doesnt not work without FOO:: (per @swordfish 's user suggestion) In your example, you are using using keyword to declare a type alias inside class Foo. This feature was added in C++ 11. When you are trying to define a class function outside of the class, that using inside the class is not visible and thus you have to prepend FOO:: to make it work. this is similar to typedef, but typedef usage would not be ideal if you wanted to declare a class Baz in the same namespace that looks like this

class Baz {
public:
    using Bar = double;
    Bar f();
};
Baz::Bar Baz::f() {
    return 42.1234;
}