1

I am facing a little problem. I need to use spdlog to log and I have custom classes. And since, spdlog is able to deal with user defined classes, I could use it log my classes.

But, I my real application, I would like to feed spdlog with a pointer of my class (because there is polymorphism but it's not the point here). And here goes my troubles. When I try to feed spdlog with a unique_ptr of my class, it does not compile.

So here a MWE:

#include <stdio.h>
#include <iostream>  
#include <fstream>
#include <string.h>  

#include <spdlog/spdlog.h>    //
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/fmt/ostr.h" // must be included to log object 

using namespace std;

struct my_type
{
    int i;
    template<typename OStream>
    friend OStream &operator<<(OStream &os, const my_type &c)
    {
        return os << "[my_type i=" << c.i << "]";
    }
};

template<typename OStream>
OStream &operator<<(OStream &os,const my_type* c)
{
    return os << "[my_type i=" << "pointer" << "]";
}

int main()  { 
    
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    spdlog::logger logger("log_test", console_sink);
    logger.set_level(spdlog::level::trace);
    auto pLog =std::make_shared<spdlog::logger>(logger); //register it if you need to access it globally
        
    std::unique_ptr<my_type> ptrA(new my_type{12});
    pLog->info("user defined type: {}", ptrA);  // of course *ptrA simply works, but in my application I have to give ptrA ...

    return 0;
}

and I get errors from the compiler gcc:

spdlog/fmt/bundled/core.h:1566:15: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = my_type; _Dp = std::default_delete<my_type>]’
const auto& arg = arg_mapper<Context>().map(val);

spdlog/fmt/bundled/core.h:1567:3: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
static_assert(

spdlog/fmt/bundled/core.h:1184:15: error: use of deleted function ‘fmt::v8::detail::fallback_formatter<T, Char, Enable>::fallback_formatter() [with T = fmt::v8::detail::unformattable; Char = char; Enable = void]’
 Formatter f;
           ^
/spdlog/fmt/bundled/core.h:963:3: note: declared here
fallback_formatter() = delete;
^~~~~~~~~~~~~~~~~~
 spdlog/fmt/bundled/core.h:1185:28: error: ‘struct fmt::v8::detail::fallback_formatter<fmt::v8::detail::unformattable, char, void>’ has no member named ‘parse’
 parse_ctx.advance_to(f.parse(parse_ctx));
                      ~~^~~~~
 spdlog/fmt/bundled/core.h:1186:22: error: ‘struct fmt::v8::detail::fallback_formatter<fmt::v8::detail::unformattable, char, void>’ has no member named ‘format’
 ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
                ~~^~~~~~

I guess the problem is comming from the interaction between template<typename OStream> OStream &operator<<(OStream &os,const my_type* c) and spdlog or fmt. So I tried to play a bit around but I am stuck.

Do you have ideas to solve this problem, keeping pLog->info("user defined type: {}", ptrA); ?

R. N
  • 707
  • 11
  • 31
  • You could always get a raw pointer from `std::unique_ptr` with `ptrA.get()`. – IlCapitano Aug 24 '21 at 21:57
  • 2
    Or since a user-defined type is involved, add an overload for `OStream &operator<<(OStream &os, const std::unique_ptr& c)` – Ted Lyngmo Aug 24 '21 at 21:59
  • @IlCapitano You are right but trying it I got `fmt/bundled/core.h:1347:47: error: call of overloaded ‘map(my_type* const&)’ is ambiguous typename Context::char_type>;` `fmt/bundled/core.h:1694:73: error: no matching function for call to 'fmt::v8:detail:arg_data >::arg_data()’ detail::mapped_type_constant::value>(args)...} {` and `fmt/bundled/core.h:1679:39: error: constexpr call flows off the end of the function static constexpr unsigned long long desc =` – R. N Aug 24 '21 at 22:43
  • @TedLyngmo It seems to be a good idea, but when I tried it out, I also got an compilation error : `spdlog/fmt/bundled/core.h:1308:5: error: static assertion failed: formatting of non-void pointers is disallowed static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); ^~~~~~~~~~~~~ ` – R. N Aug 24 '21 at 22:45
  • 1
    @R.N [Both suggestions seem to work with your example on godbolt](https://godbolt.org/z/W7n1Gbcrs). Could you update the question with a reproducible example? – IlCapitano Aug 25 '21 at 11:34
  • @IlCapitano, about the `unique_ptr` suggestion it works fine (my bad, yesterday I was tired). But you are right that things are working well on your example on godbolt. I am investigating to understand why I don't have the same result on my computer. I wonder it the problem is the version of `spdlog`... – R. N Aug 25 '21 at 12:33
  • I confirm, this issue comes from the `spdlog` version or as I suspect it comes from the difference of `fmt` versions (version 8.x. in `spdlog` 1.9.x vs version 7.0.3 in `spdlog` 1.8.0) – R. N Aug 25 '21 at 12:47

1 Answers1

0

The problem comes from the library fmt since version 8 (used by spdlog since version 1.9.0), pointers are no longer supported. A solution can be to use a wrapper class to store the pointer and precise how fmt should deal with it.

R. N
  • 707
  • 11
  • 31