1

I have an existing std::ostream-like type, which has several operator<< overloads for various types. Since that type is used as a const& argument to other APIs, I'm adding convenience factory-functions for easy inline use, at call sites.

I wrote the code below, which works fine (VS2019 and GCC9), but I was wondering several things:

  1. Do I really need the 1-arg overload? Is there benefits to having it?
  2. The 1-arg overload uses (Scott Meyers') magic-references, but should the variadic overload use them to? I tried Ts...&&, but VS2019 didn't like that.
  3. In Debug, I followed the return statements, and saw osl being move-constructed, when I was expecting Copy-Elision to take place, for such a helper, to make it zero-overhead. Is this a Debug-build artifact? Or somehow Copy-Elision cannot take place here? If so, why?
template <typename T> inline
OStreamLike bind(T&& val) {
    OStreamLike osl(1);
    osl << val;
    return osl;
}

template <typename... Ts> inline
OStreamLike bind(Ts... vals) {
    OStreamLike osl(sizeof...(Ts));
    ((osl << vals), ...);
    return osl;
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
ddevienne
  • 1,802
  • 2
  • 17
  • 28

1 Answers1

1

Do I really need the 1-arg overload? Is there benefits to having it?

1rst overload isn't required.

The only benefit is the reference to avoid copy (which might be done for the variadic overload).

The 1-arg overload uses (Scott Meyers') magic-references, but should the variadic overload use them to? I tried Ts...&&

Forwarding-reference for variadic would use Ts&&... args syntax.

but from the above code, you don't need forwarding references, regular const reference would be my choice const Ts&... args.

In Debug, I followed the return statements, and saw osl being move-constructed, when I was expecting Copy-Elision to take place, for such a helper, to make it zero-overhead. Is this a Debug-build artifact? Or somehow Copy-Elision cannot take place here? If so, why?

NRVO is not mandatory, even in C++17.

NRVO is applicable here, and I expect it at least in optimized build.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Based on your feedback, I removed the 1-arg overload, which made a call site, where `bind()` was used *inline* (i.e. as a temporary, like `exec(..., bind(...), ...)`), start to fail building. Somehow VS2019 could no longer resolve the `exec()` function being called... I tried all 3 forms, `Ts...`, `const Ts&...`, and `Ts&&...` to no avail. So I just put back the 1-arg overload, and switched to `Ts&&...` instead of `Ts...` – ddevienne Nov 10 '21 at 16:37
  • 1
    @ddevienne: No issues [here](http://coliru.stacked-crooked.com/a/8718c2996fbb438c). – Jarod42 Nov 10 '21 at 16:52
  • I have two `exec()` overloads. One w/ and one w/o an `const OStreamLike&` argument (i.e. w/ or w/o binds). Both are variadics themselves (they are specialized front-ends to `fmt::format`). They are like `exec(Arg1&, fmt::CStringRef format_str, Args&&... args)` w/o binds, and `exec(Arg1&, const OStreamLike&, fmt::CStringRef format_str, Args&&... args)` w/ binds. Sorry for leaving this out earlier. – ddevienne Nov 10 '21 at 18:03
  • I suggest to ask then another question. – Jarod42 Nov 10 '21 at 18:33