0

I'm trying to add a filename prefix to each log string in spdlog. The Spdlog formatting string looks as this:

Test log {}

Logs are written as this: spdlog::error("Test log {}", value)

I'm trying to wrap this call and concatenate additional {} before formatting string, so I can pass the prefix of the file there.

static constexpr char * prefixHolder("{} ");

template<typename... Args>
void critical(const char fmt[], Args&&... args) const
{
    constexpr auto fullFmt = prefixHolder + fmt; //I can't find any solution for this

    spdlog::critical(fullFmt, m_prefix, std::forward<Args>(args)...);
}


Log log("MyClassOrLogger");

log.critical("My format {}", value);

Is it possible to solve this at compile time? I've tried some approaches, but I haven't found any way to make input fmt argument constexpr for the compiler.

C++ 17

Any suggestions or solutions?

Thanks

Ambrase
  • 37
  • 9

1 Answers1

2

Parameter value cannot be used for constexpr.

You might turn:

template<typename... Args>
constexpr void critical(const char fmt[], Args&&... args)

into

template <char... cs, typename... Args>
void critical(std::integer_sequence<char, cs...>, Args&&... args)
{
    constexpr char fullFmt[] = {'{', '}', ' ', cs... , '\0'};

    spdlog::critical(fullFmt, m_prefix, std::forward<Args>(args)...);
}

to allow to have constexpr char array.

ensure-that-char-pointers-always-point-to-the-same-string-literal shows way to create similar sequences from literal string. In your case, it would be:

template <typename Char, Char... Cs>
constexpr auto operator"" _cs() -> std::integer_sequence<Char, Cs...> {
    return {};
}

Usage is then something like:

log.critical("My format {}"_cs, value); // gcc extension
log.critical(MAKE_SEQUENCE("My format {}"), value);

Demo with gcc extension.
Demo with MACRO.

Jarod42
  • 190,553
  • 13
  • 166
  • 271
  • It converts _cs literal to const char[] by some reason `error: no matching function for call to 'Log::critical(const char [6])' logger.critical("Hello"_cs);` MAKE_STRING example is missing aligned_string. I found a similar implementation but with 2 template parameters in one of your replies, but it fails to compile for me still. The same issue as with _cs. gcc 7.3.1 @Jarod42 – Ambrase Sep 28 '20 at 18:44
  • 1
    Code in links need some adaptations, [Demo](https://godbolt.org/z/4v7Wro) with gcc extension. – Jarod42 Sep 29 '20 at 12:59
  • Can you help with the MAKE_STRING example? The portability of the extension variant concerns me. – Ambrase Sep 29 '20 at 14:59
  • 1
    [string-interning-at-compiletime](https://stackoverflow.com/questions/50288847/string-interning-at-compiletime-for-profiling/50289055#50289055) provides `MAKE_CHAR_SEQUENCE` which give a `template struct char_sequence` that you can use instead of `std::integer_sequence`. Else you can create traits to transform the former into the later. – Jarod42 Sep 29 '20 at 15:05
  • 1
    Portable demo added. – Jarod42 Sep 29 '20 at 15:12