Description
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&
.