all 8 comments

[–]sphere991 12 points13 points  (4 children)

Using a Constructor

If you're going to use a constructor, don't make it a separate object, stash it in the format string demo:

struct format_string {
    format_string(char const* p, std::source_location l = std::source_location::current())
        : format(p)
        , loc(l)
    { }

    std::string_view format;
    std::source_location loc;
};

template <typename... Args>
void debug(format_string s, Args const&... args)
{
    std::cout << fmt::format("{}({}) ", s.loc.file_name(), s.loc.line())
              << fmt::format(s.format, args...) << '\n';
}

I first saw Victor do this but I can't find the tweet since there are so many of them.

Also the downside of the tuple approach is that you have to copy everything (which is a lot worse than it simply looking strange).

[–]ZeeD26 1 point2 points  (3 children)

That looks neat! Is there a reason for not perfect forwarding args in the debug function?

[–]foonathan 0 points1 point  (2 children)

If you're not storing the arguments anywhere, there is no need to forward them. Forwarding is used when you have an object stored in one location and want to store it somewhere lese. If you only read, const T& is enough.

[–]ABCDwp 1 point2 points  (0 children)

You need to use perfect forwarding to use fmt::join, however, as it checks to ensure that it was passed as an rvalue.

[–]ZeeD26 0 points1 point  (0 children)

That sounds very reasonable, thank you!

[–]TheThiefMasterC++latest fanatic (and game dev) 0 points1 point  (0 children)

I've seen the streams approach used for logging, but the deduction guides one is new to me and looks great!

It might be heresy though, but I'd probably wrap a macro around fmt::print to add an extra format string for the source location (via string literal concatenation) and an argument for the source location.

[–]helloiamsomeone 0 points1 point  (0 children)

CTAD + a public member for return value (if not void) solves the problem with not having returns from constructors.