Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use decltype(auto) return type to sometimes return references

I have the following code to normalize std::filesystem::path to always use forward slashes as separators:

static decltype(auto) fix_path_separator(const std::filesystem::path& path) {
    if constexpr (std::filesystem::path::preferred_separator == '/') {
        return path;
    } else {
        return std::filesystem::path{ path.generic_string() };
    }
}

I use decltype(auto) because on POSIX systems I want this function to be noop and return argument as a reference without creating a copy, but for Windows, I need a copy to modify the separators. This code appears to work and I have static_assert'ed that it indeed returns const path& on POSIX and path on Windows, but am not exactly sure how it is deduced.

I can understand the POSIX path - I am returning a variable declared as const path&, so decltype(auto) deduces const path&. But for Windows, it looks to me that I am returning a path&& as an unnamed temporary, not a path.

Can someone please provide me the decltype(auto) deduction rules which apply here?

Here is a godbolt example showcasing equivalent code.

like image 540
Dominik Kaszewski Avatar asked May 25 '26 15:05

Dominik Kaszewski


1 Answers

The return type of a function declared with decltype(auto) is deduced by substituting the operands of its (non-discarded) return statements for auto ([dcl.type.auto.deduct]/4).

In the true branch of the constexpr-if statement, this produces decltype(path), which falls under [dcl.type.decltype]/1.3 (unparenthesized id-expression naming a variable) and yields the declared type of path, namely const std::filesystem::path&.

In the other branch, the operand of decltype would be the expression std::filesystem::path { /* … */ }, which is a prvalue of type std::filesystem::path ([expr.type.conv]/1.4). This case falls under [dcl.type.decltype]/1.7, and so the resulting type is simply the type of the expression. (An rvalue reference type would be produced if the expression were an xvalue instead of a prvalue, as per [dcl.type.decltype]/1.5.)

like image 116
duck Avatar answered May 27 '26 05:05

duck