Почему разделение интерфейса и реализация специализации `std::formatter` приводят к сбою ограничений?C++

Программы на C++. Форум разработчиков
Anonymous
Почему разделение интерфейса и реализация специализации `std::formatter` приводят к сбою ограничений?

Сообщение Anonymous »

Я пытался специализировать std::formatter для базового пользовательского типа Vector3D, но получаю ошибку компилятора. Вот минимальный воспроизводимый пример:

Код: Выделить всё

vector.h
определяет класс Vector3D и определяет специализацию std::formatter, но объявляет только свою функцию формата:

Код: Выделить всё

#ifndef VECTOR_H
#define VECTOR_H

#include 

using T = float;

/* Define `Vector3D` */
struct Vector3D {
T x, y, z;

Vector3D() {}
Vector3D(T x_, T y_, T z_) : x{x_}, y{y_}, z{z_} {}
};

/* Declare specialization of `std::formatter` for `Vector3D` */
template 
struct std::formatter : public std::formatter {
auto format(const Vector3D &item, std::format_context &format_context) const;
};

#endif

Код: Выделить всё

vector.cpp
включает в себя вектор.h и определяет std::formatter::format()

Код: Выделить всё

#include "base/vector.h"

/* Define `format` function in the specialization of `std::formatter` for `Vector3D` */
auto std::formatter::format(
const Vector3D &item,
std::format_context &format_context
) const {
return std::format_to(format_context.out(), "({}, {}, {})", item.x, item.y, item.z);
}
Наконец, main.cpp пытается std::format значения типа Vector3D:

Код: Выделить всё

#include "base/vector.h"

int main()
{
std::format("{}\n", Vector3D(1, 2, 3));
}
Однако при компиляции возникает огромная ошибка компилятора:

Код: Выделить всё

/main.cpp: In function ‘int main()’:
/main.cpp:5:43: warning: ignoring return value of ‘std::string std::format(format_string, _Args&& ...) [with _Args = {Vector3D}; string = __cxx11::basic_string; format_string = basic_format_string]’, declared with attribute ‘nodiscard’ [-Wunused-result]
5 |     std::format("{}\n", Vector3D(1, 2, 3));
|                                           ^
In file included from vectors.h:4,
from /main.cpp:1:
/usr/include/c++/13/format:3742:5: note: declared here
3742 |     format(format_string __fmt, _Args&&...  __args)
|     ^~~~~~
/usr/include/c++/13/format: In instantiation of ‘static std::__format::_Arg_store::_Element_t std::__format::_Arg_store::_S_make_elt(_Tp&) [with _Tp = Vector3D; _Context = std::basic_format_context; _Args = {std::basic_format_arg::handle}; _Element_t = std::__format::_Arg_store::_Element_t]’:
/usr/include/c++/13/format:3281:23:   required from ‘std::__format::_Arg_store::_Arg_store(_Tp& ...) [with _Tp = {Vector3D}; _Context = std::basic_format_context; _Args = {std::basic_format_arg::handle}]’
/usr/include/c++/13/format:3330:14:   required from ‘auto std::make_format_args(_Args&& ...) [with _Context = basic_format_context; _Args = {Vector3D&}]’
/usr/include/c++/13/format:3743:61:   required from ‘std::string std::format(format_string, _Args&& ...) [with _Args = {Vector3D}; string = __cxx11::basic_string; format_string = basic_format_string]’
/main.cpp:5:16:   required from here
/usr/include/c++/13/format:3270:38: error: no matching function for call to ‘std::basic_format_arg::basic_format_arg(Vector3D&)’
3270 |           basic_format_arg __arg(__v);
|                                      ^~~~~
/usr/include/c++/13/format:3025:9: note: candidate: ‘template  requires  __formattable_with std::basic_format_arg::basic_format_arg(_Tp&) [with _Context = std::basic_format_context]’
3025 |         basic_format_arg(_Tp& __v) noexcept
|         ^~~~~~~~~~~~~~~~
/usr/include/c++/13/format:3025:9: note:   template argument deduction/substitution failed:
/usr/include/c++/13/format:3025:9: note: constraints not satisfied
/usr/include/c++/13/format: In substitution of ‘template  requires  __formattable_with std::basic_format_arg::basic_format_arg(_Tp&) [with _Tp = std::basic_format_context]’:
/usr/include/c++/13/format:3270:31:   required from ‘static std::__format::_Arg_store::_Element_t std::__format::_Arg_store::_S_make_elt(_Tp&) [with _Tp = Vector3D; _Context = std::basic_format_context; _Args = {std::basic_format_arg::handle}; _Element_t = std::__format::_Arg_store::_Element_t]’
/usr/include/c++/13/format:3281:23:   required from ‘std::__format::_Arg_store::_Arg_store(_Tp& ...) [with _Tp = {Vector3D}; _Context = std::basic_format_context; _Args = {std::basic_format_arg::handle}]’
/usr/include/c++/13/format:3330:14:   required from ‘auto std::make_format_args(_Args&& ...) [with _Context = basic_format_context; _Args = {Vector3D&}]’
/usr/include/c++/13/format:3743:61:   required from ‘std::string std::format(format_string, _Args&& ...) [with _Args = {Vector3D}; string = __cxx11::basic_string; format_string  = basic_format_string]’
/main.cpp:5:16:   required from here
/usr/include/c++/13/format:2226:13:   required for the satisfaction of ‘__formattable_with’ [with _Tp = Vector3D; _Context = std::basic_format_context]
/usr/include/c++/13/format:2228:7:   in requirements with ‘const _Formatter __cf’, ‘_Tp&& __t’, ‘_Context __fc’ [with _Formatter = std::formatter; _Tp = Vector3D; _Context = std::basic_format_context]
/usr/include/c++/13/format:2230:20: note: the required expression ‘__cf.format(__t, __fc)’ is invalid
2230 |       { __cf.format(__t, __fc) } -> same_as;
|         ~~~~~~~~~~~^~~~~~~~~~~
/usr/include/c++/13/format: In instantiation of ‘static std::__format::_Arg_store::_Element_t std::__format::_Arg_store::_S_make_elt(_Tp&) [with _Tp = Vector3D; _Context = std::basic_format_context; _Args = {std::basic_format_arg::handle}; _Element_t = std::__format::_Arg_store::_Element_t]’:
/usr/include/c++/13/format:3281:23:   required from ‘std::__format::_Arg_store::_Arg_store(_Tp& ...) [with _Tp = {Vector3D}; _Context = std::basic_format_context; _Args = {std::basic_format_arg::handle}]’
/usr/include/c++/13/format:3330:14:   required from ‘auto std::make_format_args(_Args&& ...) [with _Context = basic_format_context; _Args = {Vector3D&}]’
/usr/include/c++/13/format:3743:61:   required from ‘std::string std::format(format_string, _Args&& ...) [with _Args = {Vector3D}; string = __cxx11::basic_string; format_string = basic_format_string]’
/main.cpp:5:16:   required from here
cc1plus: note: set ‘-fconcepts-diagnostics-depth=’ to at least 2 for more detail
/usr/include/c++/13/format:2837:7: note: candidate: ‘std::basic_format_arg::basic_format_arg() [with _Context = std::basic_format_context]’
2837 |       basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
|       ^~~~~~~~~~~~~~~~
/usr/include/c++/13/format:2837:7: note:   candidate expects 0 arguments, 1 provided
/usr/include/c++/13/format:2775:11: note: candidate: ‘constexpr std::basic_format_arg::basic_format_arg(const std::basic_format_arg&)’
2775 |     class basic_format_arg
|           ^~~~~~~~~~~~~~~~
/usr/include/c++/13/format:2775:11: note:   no known conversion for argument 1 from ‘Vector3D’ to ‘const std::basic_format_arg&’
/usr/include/c++/13/format:2775:11: note: candidate: ‘constexpr std::basic_format_arg::basic_format_arg(std::basic_format_arg&&)’
/usr/include/c++/13/format:2775:11: note:   no known conversion for argument 1 from ‘Vector3D’ to ‘std::basic_format_arg&&’
Однако, когда я просто определяю функцию формата непосредственно в заголовочном файле Vector.h, все работает. Может кто-нибудь объяснить, что здесь происходит?

Подробнее здесь: https://stackoverflow.com/questions/787 ... tter-speci

Вернуться в «C++»