Skip to content

[BUG] forwarding a member of class from method with const this returns non-const reference that drops const #274

Closed
@filipsajdak

Description

@filipsajdak

In the current implementation (a981011) cppfront does not handle forwarding of class attributes well. The following code:

spec: type = {
    name:        std::string = "spec";
    get_name: (in    this) -> forward std::string = this.name;
    get_name: (inout this) -> forward std::string = this.name;
}

Generates:

class spec  {
    private: std::string name {"spec"}; 
    public: [[nodiscard]] auto get_name() const -> std::string& { return (*this).name; }
    public: [[nodiscard]] auto get_name() -> std::string& { return (*this).name; }
}

When compiles using cpp1 compiler:

../tests/type_forward.cpp2:4:74: error: binding reference of type 'basic_string<...>' to value of type 'const basic_string<...>' drops 'const' qualifier
    public: [[nodiscard]] auto get_name() const -> std::string& { return (*this).name; }

Expectation

I expect to get std::string const& when forwarding the member of the class when in this is used (explicitly or implicitly). I can now achieve that by adding const to the return type:

    get_name: (in    this) -> forward const std::string = this.name;

that will generate:

    public: [[nodiscard]] auto get_name() const -> std::string const& { return (*this).name; }

That works but breaks the idea of writing intentions rather expected generated code.

Side notes

Playing a little bit with that I come to the conclusion that what I am missing here is something that will mimic Deducing this (P0847). I imagine writing something like the following:

spec: type = {
    name:        std::string = "spec";
    get_name: (this : _) -> forward std::string = this.name; 
    // alternatively: get_name: (deduce this) -> forward std::string = this.name;
}

I understand that P0847 is a C++23 feature that is not yet implemented by our supported compilers but maybe we can mimic it here somehow? Using that syntax we could at least generate both versions of methods (const & non-const).

I am also a little disapointed with version that returns forward _. The following code:

    get_name: (in    this) -> forward _ = this.name;
    get_name: (inout this) -> forward _ = this.name;

Generates:

    public: [[nodiscard]] auto get_name() const -> decltype(auto) { return (*this).name; }
    public: [[nodiscard]] auto get_name() -> decltype(auto) { return (*this).name; }

In both methods return type is deduced to std::string. What I was expecting was behaviour like with return type auto&& which for non-const version returns std::string& and for const version returns std::string const&.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions