Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formatting Custom Objects Example Doesn't work #3097

Closed
cuppajoeman opened this issue May 26, 2024 · 7 comments
Closed

Formatting Custom Objects Example Doesn't work #3097

cuppajoeman opened this issue May 26, 2024 · 7 comments

Comments

@cuppajoeman
Copy link

In the quickstart page 1, we have:

#include "spdlog/spdlog.h"
#include "spdlog/fmt/ostr.h" // must be included
#include "spdlog/sinks/stdout_sinks.h"

class some_class {};
std::ostream& operator<<(std::ostream& os, const some_class& c)
{ 
    return os << "some_class"; 
}

void custom_class_example()
{
    some_class c;
    auto console = spdlog::stdout_logger_mt("console");
    console->info("custom class with operator<<: {}..", c);
}

building this example yields the following error:

cdIn file included from /home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/format.h:49,
                 from /home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/ostream.h:21,
                 from /home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/ostr.h:19,
                 from /home/ccn/temp/spdlog/main.cpp:1:
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/core.h: In instantiation of ‘fmt::v10::detail::value<Context> fmt::v10::detail::make_arg(T&) [with bool PACKED = true; Context = fmt::v10::basic_format_context<fmt::v10::appender, char>; T = some_class; typename std::enable_if<PACKED, int>::type <anonymous> = 0]’:
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/core.h:1842:51:   required from ‘fmt::v10::format_arg_store<Context, Args>::format_arg_store(T& ...) [with T = {some_class}; Context = fmt::v10::basic_format_context<fmt::v10::appender, char>; Args = {some_class}]’
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/core.h:1860:18:   required from ‘constexpr fmt::v10::format_arg_store<Context, typename std::remove_cv<typename std::remove_reference<T>::type>::type ...> fmt::v10::make_format_args(T& ...) [with Context = basic_format_context<appender, char>; T = {some_class}]’
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/logger.h:328:75:   required from ‘void spdlog::logger::log_(spdlog::source_loc, spdlog::level::level_enum, spdlog::string_view_t, Args&& ...) [with Args = {some_class&}; spdlog::string_view_t = fmt::v10::basic_string_view<char>]’
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/logger.h:80:13:   required from ‘void spdlog::logger::log(spdlog::source_loc, spdlog::level::level_enum, fmt::v10::format_string<T ...>, Args&& ...) [with Args = {some_class&}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, some_class&>]’
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/logger.h:85:12:   required from ‘void spdlog::logger::log(spdlog::level::level_enum, fmt::v10::format_string<T ...>, Args&& ...) [with Args = {some_class&}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, some_class&>]’
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/logger.h:140:12:   required from ‘void spdlog::logger::info(fmt::v10::format_string<T ...>, Args&& ...) [with Args = {some_class&}; fmt::v10::format_string<T ...> = fmt::v10::basic_format_string<char, some_class&>]’
/home/ccn/temp/spdlog/main.cpp:13:16:   required from here
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/core.h:1604:7: 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
 1604 |       formattable,
      |       ^~~~~~~~~~~
/home/ccn/temp/spdlog/external_libraries/spdlog/include/spdlog/fmt/bundled/core.h:1604:7: note: ‘formattable’ evaluates to false
 make[2]: *** [CMakeFiles/MyProject.dir/build.make:76: CMakeFiles/MyProject.dir/main.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:100: CMakeFiles/MyProject.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
@tt4g
Copy link
Contributor

tt4g commented May 26, 2024

Have you tried another sample?

#include <iterator>

#include "spdlog/spdlog.h"
#include "spdlog/fmt/ostr.h" // must be included
#include "spdlog/sinks/stdout_sinks.h"

class some_class {
    int code;
};

template<typename OStream>
friend OStream &operator<<(OStream &os, const some_class& to_log)
{
    fmt::format_to(std::ostream_iterator<char>(os), "{:04X}", to_log.code);
    return os;
}

void custom_class_example()
{
    some_class c; c.code = 17;
    auto console = spdlog::stdout_logger_mt("console");
    console->info("custom class with operator<< using fmt: {}..", c);
}

Also, did you check the link to the official fmt documentation (https://fmt.dev/latest/api.html#udt) in the error message?

@cuppajoeman
Copy link
Author

Have you tried another sample?

#include <iterator>

#include "spdlog/spdlog.h"
#include "spdlog/fmt/ostr.h" // must be included
#include "spdlog/sinks/stdout_sinks.h"

class some_class {
    int code;
};

template<typename OStream>
friend OStream &operator<<(OStream &os, const some_class& to_log)
{
    fmt::format_to(std::ostream_iterator<char>(os), "{:04X}", to_log.code);
    return os;
}

void custom_class_example()
{
    some_class c; c.code = 17;
    auto console = spdlog::stdout_logger_mt("console");
    console->info("custom class with operator<< using fmt: {}..", c);
}

Also, did you check the link to the official fmt documentation (https://fmt.dev/latest/api.html#udt) in the error message?

I tried the example you provided which also errors out the same way. I'm using

CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # allows for language servers to understand the codebase
set(CMAKE_LINKER_TYPE MOLD) # use a modern linker
project(MyProject)

# Specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# Add spdlog directory
add_subdirectory(external_libraries/spdlog)
# include_directories(external_libraries/spdlog/include)

# Add executable
add_executable(MyProject main.cpp)

# Link spdlog
target_link_libraries(MyProject PRIVATE spdlog::spdlog)

I looked at the fmt documentation. Note that my question issue is in relation to the first example which has the following language:

image

Due to the usage of "or" here I assumed that the first example wouldn't have to do anything much with fmt.

Either way let me know if you see any incorrect usage of spdlog or if this is an actual problem.

@tt4g
Copy link
Contributor

tt4g commented May 27, 2024

I noticed that this is a breaking change in fmt version 10 (fmtlib/fmt#3318).
The Wiki example seems to be out of date.

The following changes should work, please try it.

 #include "spdlog/spdlog.h"
 #include "spdlog/fmt/ostr.h" // must be included
 #include "spdlog/sinks/stdout_sinks.h"
 
 class some_class {};
 std::ostream& operator<<(std::ostream& os, const some_class& c)
 { 
     return os << "some_class"; 
 }
+
+template <> struct fmt::formatter<some_class> : fmt::ostream_formatter {};

 void custom_class_example()
 {
     some_class c;
     auto console = spdlog::stdout_logger_mt("console");
     console->info("custom class with operator<<: {}..", c);
 }

@ChangXiaoxin
Copy link

+template <> struct fmt::formatter<some_class> : fmt::ostream_formatter {};

Hi, I got the same compile issue, and fixed with this change in my case, thank you so much!

@gabime gabime closed this as completed Jun 2, 2024
@cuppajoeman
Copy link
Author

cuppajoeman commented Jun 12, 2024

Just writing this to confirm that the newest information in the docs fixes it

@harryjwright
Copy link

Can I create a template out of the, uh, template fix?

I assumed

template <typename T> struct formatter<T>: ostream_formatter{};

would work, but it doesn't. I'm sick of having to append it to every custom class.

@tt4g
Copy link
Contributor

tt4g commented Oct 31, 2024

@harryjwright This feature is provided by fmt. Please ask in the fmt repository.

Tip

From the latest documentation, it seems that fmt::formatter<T> can define several types of formats with std::enable_if_t: https://fmt.dev/11.0/api/#formatting-user-defined-types

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants