1

Why does the compiler complain that returning Settings is undefined, while it's perfectly happy accepting it as an argument?

foo.hpp

class Foo {
  public:
     typedef struct{
         int id;
     } Settings;

     Settings GetSettings();
     void SetSettings(Settings settings);
};

foo.cpp

// nope
Settings Foo::GetSettings(){
}

// no problem
void Foo::SetSettings(Settings settings){

}
  • 3
    It's because of [argument dependent lookup](https://stackoverflow.com/questions/8111677/what-is-argument-dependent-lookup-aka-adl-or-koenig-lookup). – 1201ProgramAlarm Apr 16 '20 at 18:39

1 Answers1

4

You need to tell the compiler that Settings is in the scope of Foo, since that's where it's defined.

This compiles just fine:

//foo.cpp

Foo::Settings Foo::GetSettings(){
}

Inside the class, you don't need to specify that, since the compiler considers all names in the scope of the class.

In this definition,

//foo.cpp

void Foo::SetSettings(Settings settings){
}

the compiler knows that you are defining a function of Foo, so similarly, you don't have to specify the scope that the compiler should look at, for the function argument Settings.

It might seem that the compiler should know that GetSettings is also a function of Foo. This is mostly right, and in fact, this compiles just fine:

auto Foo::GetSettings() -> Settings {
}

In this case, the compiler knows in which scope to look for the return type, by the time it has to figure it out.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • `the compiler knows that you are defining a function of Foo` - how can that not be said for both methods? – terratermatwoa Apr 16 '20 at 18:41
  • @terratermatwoa added more explanation. – cigien Apr 16 '20 at 18:46
  • Thanks.. Still seems "wrong". The compiler is really guessing that `Settings` is of `Foo::` in the setter function. It could be some other struct..But I guess that's how it is. – terratermatwoa Apr 16 '20 at 18:48
  • 1
    @terratermatwoa the compiler probably could work out that you are defining a method but the standard says its not allowed to, the compiler reads the tokens in order and at the point it reads the `Settings` token it doesn't know that the next tokens will tell it that its the return type of a method in `Foo` – Alan Birtles Apr 16 '20 at 18:48
  • 2
    @terratermatwoa -- when it sees that initial `Settings` the compiler doesn't know that it's compiling a member function of the class `Foo`. It doesn't know that until it sees the `Foo::` that starts the member function name. And it's not allowed to go back; all it can do is complain. So you need to say `Foo::` for **both** `Foo::Settings` and `Foo::GetSettings`; the first one says that the return type is a member of `Foo` and the second one says that the function is a member of `Foo`. – Pete Becker Apr 16 '20 at 18:48