Re[31]: Cоздание базового шаблона минуя специализацию
От: so5team https://stiffstream.com
Дата: 28.10.22 12:56
Оценка:
Здравствуйте, rg45, Вы писали:

S>>Простите, общие слова не интересны. Конкретные примеры -- да, абстрактные рассуждения о том, как у кого-то где-то что-то -- нет.


R>А чего вы решаете за всех что интересно, что нет?


На публичном форуме вы ответили мне, и мне же высказали, что я проигнорировал часть ваших слов. В этом общении между мной и вами я решаю что интересно мне, а вы -- что вам.

Вроде бы по другому и не бывает?

R>Это ж форум, а не личная переписка.


Именно. Я же не затыкаю вам рот, не указываю что говорить, а что нет.
То, что написано вами здесь и остается и если кто-то заинтересуется тем, что вы высказали, то этот кто-то сможет продолжить разговор с заинтересовавшего его (её) места.
Re[21]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 28.10.22 14:26
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>Хотя в случае с функциями была простая перегрузка, типа:
V>template<htlib::v2::uint_t dimensions, typename other_t>
V>void formatter(const htlib::v2::pointxd_t<dimensions, other_t>&);
V>


+1

Или вот еще интересный сценарий: подход с функциями позволяет, например, легко определить один общий форматтер (или фиксированный набор форматтеров) для всех пользовательских типов, объединенных общим пространством имен. Это может быть как простая шаблонная функция, так и просто using declaration, вносящее имя функции, определенной в каком-то другом пространстве имен. (И разумеется, никто при этом не запрещает использовать в этом же пространсве имен и другие, более специальные форматтеры наряду с общим, если нужно). В подходе со специализациями шаблона класса придется написать тонны кода и постоянно расширять при добавлении новых типов.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 28.10.2022 14:32 rg45 . Предыдущая версия . Еще …
Отредактировано 28.10.2022 14:31 rg45 . Предыдущая версия .
Отредактировано 28.10.2022 14:30 rg45 . Предыдущая версия .
Отредактировано 28.10.2022 14:29 rg45 . Предыдущая версия .
Re[22]: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 28.10.22 18:01
Оценка: +2
Здравствуйте, rg45, Вы писали:

R>Или вот еще интересный сценарий: подход с функциями позволяет, например, легко определить один общий форматтер (или фиксированный набор форматтеров) для всех пользовательских типов, объединенных общим пространством имен. Это может быть как простая шаблонная функция, так и просто using declaration, вносящее имя функции, определенной в каком-то другом пространстве имен. (И разумеется, никто при этом не запрещает использовать в этом же пространсве имен и другие, более специальные форматтеры наряду с общим, если нужно). В подходе со специализациями шаблона класса придется написать тонны кода и постоянно расширять при добавлении новых типов.


Да, все богатые возможности перегрузки функций идут лесом. Сейчас, переписывая форматеры своих типов я постоянно налетаю на грабли ограничении специализации класса.
Re[19]: Cоздание базового шаблона минуя специализацию
От: so5team https://stiffstream.com
Дата: 29.10.22 06:43
Оценка: 20 (3)
Здравствуйте, rg45, Вы писали:

R>Так о том и речь, что их нет, а вместо функций — шаблон класса std::formatter. А если бы std::format для кастомизации использовал бы не шаблон класса со специализациями, а неквалифицированный вызов функции с каким-то предопределенным именем, это могло бы дать ряд преимуществ:


Могу ошибаться, но может быть есть способ объединить лучшее из двух миров?

Идея в том, что сейчас fmtlib просто инстанциирует тип formatter там, где ей это нужно. Наверное, можно создавать formatter не напрямую, а вызвав функцию-фабрику, которая уже и возвратит экземпляр formatter.

Функция-фабрика будет свободной функцией, которая может быть определена и в пространстве имен пользователя.

Небольшой набросок слепленный на коленке для того, чтобы продемонстрировать идею:
  откровенный колхозинг
#include <algorithm>
#include <iostream>
#include <string>
#include <string_view>
#include <type_traits>
#include <sstream>

namespace fmtlib
{

template<typename T, typename CharT = char>
struct formatter;

template<typename CharT, typename T>
[[nodiscard]]
formatter<T, CharT>
make_formatter(const T &);

template<typename CharT, typename T>
CharT *
format(CharT * dest, T && value)
    {
        return make_formatter<CharT>(value).format(dest, value);
    }

template<>
struct formatter<std::string_view, char>
    {
        char *
        format(char * dest, const std::string_view & v)
            {
                *(dest++) = '"';
                std::copy(v.begin(), v.end(), dest);
                dest += v.size();
                *(dest++) = '"';
                return dest;
            }
    };

template<>
struct formatter<std::string, char>
    :    public formatter<std::string_view, char>
    {
        char *
        format(char * dest, const std::string & v)
            {
                return formatter<std::string_view, char>::format(
                        dest, std::string_view{v});
            }
    };

template<>
struct formatter<char, char>
    {
        char *
        format(char * dest, const char v)
            {
                *(dest++) = v;
                return dest;
            }
    };

template<typename T>
struct formatter<T, std::enable_if_t<std::is_arithmetic_v<T>, char>>
    {
        char *
        format(char * dest, const T & v)
            {
                std::ostringstream ss;
                ss << v;
                const auto sv = ss.str();
                std::copy(sv.begin(), sv.end(), dest);
                dest += sv.size();
                return dest;
            }
    };

template<typename CharT, typename T>
[[nodiscard]]
formatter<T, CharT>
make_formatter(const T &)
    {
        return {};
    }

} /* namespace fmtlib */

namespace one
{

template<typename T>
struct point
    {
        T x;
        T y;
    };

} /* namespace one */

template<typename T>
struct fmtlib::formatter<one::point<T>, char>
    {
        char *
        format(char * dest, const one::point<T> & v)
        {
            dest = fmtlib::format(dest, '{');
            dest = fmtlib::format(dest, v.x);
            dest = fmtlib::format(dest, ',');
            dest = fmtlib::format(dest, v.y);
            dest = fmtlib::format(dest, '}');
            return dest;
        }
    };

namespace two
{

template<typename T, typename Tag>
struct value_holder
    {
        T v;
    };

template<typename T, typename Tag, typename CharT>
struct value_holder_formatter
    {
        CharT *
        format(CharT * dest, const value_holder<T, Tag> & v)
        {
            return fmtlib::formatter<T, CharT>{}.format(dest, v.v);
        }
    };

template<typename CharT, typename T, typename Tag>
value_holder_formatter<T, Tag, CharT>
make_formatter(const value_holder<T, Tag> &)
    {
        return {};
    }

} /* namespace two */

int
main()
    {
        using namespace std::string_literals;
        using namespace std::string_view_literals;

        char buf[1024];

        struct tag_1 {};
        struct tag_2 {};

        char * p = fmtlib::format(buf, 42);
        p = fmtlib::format(p, ' ');
        p = fmtlib::format(p, "is the answer"s);
        p = fmtlib::format(p, ';' );
        p = fmtlib::format(p, one::point<int>{3,4});
        p = fmtlib::format(p, '-' );
        p = fmtlib::format(p, one::point<float>{0.1,-1.2});
        p = fmtlib::format(p, ';' );
        p = fmtlib::format(p, two::value_holder<short, tag_1>{333});
        p = fmtlib::format(p, '-' );
        p = fmtlib::format(p, two::value_holder<unsigned long long, tag_2>{555});
        *p = 0;

        std::cout << "Result: " << buf << std::endl;
    }

Проверялось на g++-11 в режиме C++17


Не знаю насколько реально все это впилить в fmtlib, т.к. там тип formatter нужен для вложенного типа basic_format_context::formatter_type. Но если реально, то можно расширить функциональность fmtlib сохранив при этом совместимость с уже имеющимся кодом, в котором делаются специализации fmt::formatter. И, соответственно, подобный же трюк можно будет проделать и с std::format.
Re[20]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 29.10.22 10:03
Оценка: +1
Здравствуйте, so5team, Вы писали:

S>Могу ошибаться, но может быть есть способ объединить лучшее из двух миров?


S>Идея в том, что сейчас fmtlib просто инстанциирует тип formatter там, где ей это нужно. Наверное, можно создавать formatter не напрямую, а вызвав функцию-фабрику, которая уже и возвратит экземпляр formatter.


S>Функция-фабрика будет свободной функцией, которая может быть определена и в пространстве имен пользователя.


Вот такое решение мне нравится гораздо больше. С одной стороны, обеспечивается обратная совместимость с уже написанными форматтерами в виде специализаций. При этом появляются новые возможности, о которых говорилось выше:


В конце концов, с таким подходом пользователь может самостоятельно осуществить переход от форматтеров-классов к форматтерам-функциям, если очень хочется. А может использовать какие-то более сложные гибридные схемы. Вместо одной точки кастомизации теперь их целых три: специализация библиотечного шаблона класса; фабрики форматтеров; пользовательский форматтер. Пользовательский форматтер вообще можно навернуть с какой угодно сложностью и обеспечить еще 100500 точек кастомизации, специфичных для прикладной области. В целом гибкость и юзабельность существенно лучше, чем в текущем подходе со специализациями.

--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 29.10.2022 11:05 rg45 . Предыдущая версия . Еще …
Отредактировано 29.10.2022 11:03 rg45 . Предыдущая версия .
Отредактировано 29.10.2022 10:58 rg45 . Предыдущая версия .
Отредактировано 29.10.2022 10:57 rg45 . Предыдущая версия .
Отредактировано 29.10.2022 10:56 rg45 . Предыдущая версия .
Отредактировано 29.10.2022 10:31 rg45 . Предыдущая версия .
Отредактировано 29.10.2022 10:04 rg45 . Предыдущая версия .
Re[20]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 29.10.22 18:35
Оценка:
Здравствуйте, so5team, Вы писали:

S>Идея в том, что сейчас fmtlib просто инстанциирует тип formatter там, где ей это нужно. Наверное, можно создавать formatter не напрямую, а вызвав функцию-фабрику, которая уже и возвратит экземпляр formatter.


S>Функция-фабрика будет свободной функцией, которая может быть определена и в пространстве имен пользователя.


S>
S>template<typename T, typename CharT = char>
S>struct formatter;
S>


Можно сделать еще один шажок навстречу пользователю и для основного шаблона formatter предоставить определение, которое будет делегировать вызов (через ADL) пользовательстким функциям parse и format. Тогда у пользователя будет три возможности: специализировать библиотечный formatter, определить собственный форматтер с фабрикой, либо просто определить функции parse и format в том же пространстве имен, что и пользовательский тип (типы). Это для тех типов, которые не требуют передачи состояния между parse и format. Что-то мне подсказывает, что таких типов будет большинство.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 29.10.2022 18:48 rg45 . Предыдущая версия .
Re[20]: Cоздание базового шаблона минуя специализацию
От: _NN_ www.nemerleweb.com
Дата: 29.10.22 21:44
Оценка: 1 (1) +1
Здравствуйте, so5team, Вы писали:

Может в https://stdcpp.ru стоит написать ?
А там гляди и лет через 10 в стандарт придёт.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[21]: Cоздание базового шаблона минуя специализацию
От: so5team https://stiffstream.com
Дата: 30.10.22 06:00
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>Может в https://stdcpp.ru стоит написать ?

_NN>А там гляди и лет через 10 в стандарт придёт.

ИМХО, в данном случае логичнее было бы идти через модификацию fmtlib. Если такое изменение в принципе возможно, то внедрить его будет гораздо быстрее, затем можно будет собрать актуальный фидбэк от пользователей, и уже на основании фидбэка обновлять стандарт. Тем более, что скоуп C++23 уже вроде как зафиксировали, новое туда добавлять не будут. А до C++26 можно будет потренироваться на кошках.

Только вот в ближайшее пару месяцев у меня лично возможности заняться pull-request-ом для fmtlib не будет
Re[3]: Cоздание базового шаблона минуя специализацию
От: PM  
Дата: 30.10.22 08:27
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Наверное вопрос в этом, как выкрутится теперь. Ситуация простая. У std::formatter есть специализация для вывода std::chrono::duration<>. У меня в библиотеках везде используется своя специализация времени:
V>using reftime_t = std::chrono::duration<int64, std:ratio<1, 10000000>>;
V>
Стандартные возможности форматирования огромны, но мне хочется их расширить для своего типа времени и переиспользовать. Таким образом объявляя
V>template <>
V>struct std::formatter<reftime_t> {
V>    // ...
V>};
V>
я автоматически лишаюсь возможности вызвать стандартную реализацию и вынужден повторять всю логику заново. Это не дело, я считаю


Смотрю код новой библиотеки логирования xtr. В ней чтобы форматировать `std::timespec` по-своему, автор сделал свой тип простым наследованием от стандартной структуры:
namespace xtr
{
    struct timespec : std::timespec
    {
        timespec() = default;

        timespec(std::timespec ts) : std::timespec(ts)
        {
        }
    };
}

template<>
struct fmt::formatter<xtr::timespec>
{
    template<typename ParseContext>
    constexpr auto parse(ParseContext& ctx)
    {
        return ctx.begin();
    }

    template<typename FormatContext>
    auto format(const xtr::timespec ts, FormatContext& ctx)
    {
        std::tm temp;
        return fmt::format_to(
            ctx.out(),
            "{:%Y-%m-%d %T}.{:06}",
            *::gmtime_r(&ts.tv_sec, &temp),
            ts.tv_nsec / 1000);
    }
};

https://github.com/choll/xtr/blob/master/single_include/xtr/logger.hpp#L70L105
Re[21]: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 30.10.22 11:40
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>В конце концов, с таким подходом пользователь может самостоятельно осуществить переход от форматтеров-классов к форматтерам-функциям, если очень хочется. А может использовать какие-то более сложные гибридные схемы. Вместо одной точки кастомизации теперь их целых три: специализация библиотечного шаблона класса; фабрики форматтеров; пользовательский форматтер. Пользовательский форматтер вообще можно навернуть с какой угодно сложностью и обеспечить еще 100500 точек кастомизации, специфичных для прикладной области. В целом гибкость и юзабельность существенно лучше, чем в текущем подходе со специализациями.


Если можно подсунуть функцию фабрику-форматеров в своё пространство имен, то при желании, можно создать у себя универсальный форматтер для всех типов, который уже будет вызывать специализированные функции форматеры или реализовывать любые другие практики принятые в конкретном проекте.
Re[4]: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 30.10.22 11:51
Оценка:
Здравствуйте, PM, Вы писали:

PM>Смотрю код новой библиотеки логирования xtr. В ней чтобы форматировать `std::timespec` по-своему, автор сделал свой тип простым наследованием от стандартной структуры:


Если оставить за скобками то, что его подход с наследованием является очень опасной практикой, автор решает ту же проблему, что и я — у меня в мультимедиа время, это дискретная величина и мне нельзя выводить его с округлением, как это предлагает делать libfmt. А от чего будет наследоваться автор, если ему понадобиться изменить или расширить форматирование int ?
Re[22]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 30.10.22 14:30
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Если можно подсунуть функцию фабрику-форматеров в своё пространство имен, то при желании, можно создать у себя универсальный форматтер для всех типов, который уже будет вызывать специализированные функции форматеры или реализовывать любые другие практики принятые в конкретном проекте.


Но есть нюанс: все это будет работать только для типов, определенных пользователем (и производных от них, наподобие std::vector<MyClass>). Настройка форматирования для встроенных типов по-прежнему остается нерешенной проблемой, даже в этом подходе.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Cоздание базового шаблона минуя специализацию
От: PM  
Дата: 30.10.22 15:45
Оценка:
Здравствуйте, Videoman, Вы писали:

PM>>Смотрю код новой библиотеки логирования xtr. В ней чтобы форматировать `std::timespec` по-своему, автор сделал свой тип простым наследованием от стандартной структуры:


V>Если оставить за скобками то, что его подход с наследованием является очень опасной практикой, автор решает ту же проблему, что и я — у меня в мультимедиа время, это дискретная величина и мне нельзя выводить его с округлением, как это предлагает делать libfmt. А от чего будет наследоваться автор, если ему понадобиться изменить или расширить форматирование int ?


По-моему, наследование для создания другого типа — вполне безопасная, рабочая альтернатива варианту с strong typedef, который предложил коллега so5team.

Думаю, подавляющее большинство сценариев использования — форматировать пользовательские типы, и это вполне работает. Надеюсь автор fmtlib сможет расширить ее для вашего случая, но в std::format это навряд ли уже случится.
Re: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 02.11.22 13:52
Оценка: 8 (1)
В общем для всех тех, кто активно участвовал в дискуссии, критиковал и помогал решать вопрос с форматированием, наталкивая на правильные решения — возможно будет интересно! Кажется вот возможное решение:
#include <string>
#include <iostream>
#include <typeinfo>
#include <utility>

#include <fmt/core.h>
#include <fmt/chrono.h>
#include <fmt/xchar.h>

namespace my
{
// rg45 forward wrapper

template <typename T>
struct wrapper
{
    T t;

    explicit wrapper(T&& t) : t(std::forward<T>(t)) {}

    T&& forward() { return std::forward<T>(t); }
};

template <typename T>
wrapper<T> wrap(T&& t) { return wrapper<T>(std::forward<T>(t)); }



// own format wrapper

template<typename... Params>
std::string format(const std::string_view& format_string, Params&& ...params)
{
    return fmt::format(format_string, wrap(params)...);
}

} // namespace my



// dispatch formatter

template<typename char_t, typename type_t>
class fmt::formatter<my::wrapper<type_t>, char_t>
{
public:
    constexpr auto parse(basic_format_parse_context<char_t>& ctx) -> decltype(ctx.begin())
    {
        auto it = ctx.begin();
        auto end = ctx.end();

        it = std::find(it, end, '}');

        if (it != end && *it != '}')
            throw format_error("invalid format");

        return it;
    }

    template<typename it_t>
    auto format(my::wrapper<type_t>& data, basic_format_context<it_t, char_t>& ctx) const -> decltype(ctx.out())
    {
        return format_to(ctx.out(), "***{}***", data.forward());
    }
};



// test

int main()
{
    std::cout << my::format("{} | {} | {:.e}", 1, "str", 2.5);
}

***1*** | ***str*** | ***2.5***


Это как идея и код для подумать. Думаю тут всё понятно. Можно из форматера дергать свои функции с нужной себе логикой, кастомизировать стандартные и примитивные типы, вызывать std::форматтеры, если надо и т.д.
Хорошо бы проверить будет ли такое работать с std::format C++20.
Re[2]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 02.11.22 14:17
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>
V>template<typename... Params>
V>std::string format(const std::string_view& format_string, Params&& ...params)
V>{
V>    return fmt::format(format_string, wrap(params)...);
V>}
V>



    return fmt::format(format_string, wrap(std::forward<Params>(params))...);



При вызове wrap разве не нужно форвардить? Если не форвардить, то все params всегда будут интерпретироваться как lvalue выражения и врапиться по lvalue ссылкам. Если так и было задумано, то с форвардингом можно было вообще не заморачиваться, просто биндить всегда по константрой lvalue ссылке.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 02.11.22 14:21
Оценка:
Здравствуйте, rg45, Вы писали:

R>При вызове wrap разве не нужно форвардить? Если не форвардить, то все params всегда будут интерпретироваться как lvalue выражения и врапиться по lvalue ссылкам. Если так и было задумано, то с форвардингом можно было вообще не заморачиваться, просто биндить всегда по константрой lvalue ссылке.


Нужно конечно! Это я пропустил, спешил проверить идею .
Re[2]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 02.11.22 20:57
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Это как идея и код для подумать. Думаю тут всё понятно. Можно из форматера дергать свои функции с нужной себе логикой, кастомизировать стандартные и примитивные типы, вызывать std::форматтеры, если надо и т.д.


То есть, мы враппим std:/fmt:: format и дальше пользуемся только своим my::format. А formatter специализируем только один раз и пишем его так, что он делегирует вызовы пользовательским функциям с использованием ADL. Пожалуй, это будет работать, причем, даже для встроенных типов. Только для встроенных типов нужно будет заимплементить соответствующие функции в глобальном пространстве имен, причем так, чтоб их объявления (как минимум) были видны из нашей единственной специализации форматтера. Правильно я понял идею?

Один нюанс: необходимость определения функций в глобальном пространстве имен для встроенных типов будет диктовать выбор каких-то достаточно оригинальных имен для этих функций, чтобы исключить возможность нечаянных коллизий. Другой способ решения этой проблемы: добавление какого-нибудь фиктивного параметра, имеющего тип, определенный в пространстве имен my. При таком подходе имена для функций можно будет выбрать максимально простые и комфортные и перенести определения самих функций из глобального пространства имен в пространство имен my (это только для встроенных типов — для пользовательских типов функции можно будет спокойно определять в том же пространстве имен, что и сами типы).

V>Хорошо бы проверить будет ли такое работать с std::format C++20.


Ну а почему нет, подходы же одинаковые.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 02.11.2022 21:07 rg45 . Предыдущая версия . Еще …
Отредактировано 02.11.2022 21:01 rg45 . Предыдущая версия .
Re[3]: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 03.11.22 09:14
Оценка:
Здравствуйте, rg45, Вы писали:

R>То есть, мы враппим std:/fmt:: format и дальше пользуемся только своим my::format. А formatter специализируем только один раз и пишем его так, что он делегирует вызовы пользовательским функциям с использованием ADL. Пожалуй, это будет работать, причем, даже для встроенных типов. Только для встроенных типов нужно будет заимплементить соответствующие функции в глобальном пространстве имен, причем так, чтоб их объявления (как минимум) были видны из нашей единственной специализации форматтера. Правильно я понял идею?


Не совсем. Всё так, но не понятно зачем в глобальном пространстве, когда можно в локальном. Класс диспетчера-то наш и мы вольны вызывать что хотим.

R>Один нюанс: необходимость определения функций в глобальном пространстве имен для встроенных типов будет диктовать выбор каких-то достаточно оригинальных имен для этих функций, чтобы исключить возможность нечаянных коллизий. Другой способ решения этой проблемы: добавление какого-нибудь фиктивного параметра, имеющего тип, определенный в пространстве имен my. При таком подходе имена для функций можно будет выбрать максимально простые и комфортные и перенести определения самих функций из глобального пространства имен в пространство имен my (это только для встроенных типов — для пользовательских типов функции можно будет спокойно определять в том же пространстве имен, что и сами типы).


Опять не понимаю. Зачем это делать в глобальном пространстве, можно ведь:
// dispatch formatter

template<typename char_t, typename type_t>
class fmt::formatter<my::wrapper<type_t>, char_t>
{
public:
    constexpr auto parse(basic_format_parse_context<char_t>& ctx) -> decltype(ctx.begin())
    {
        return my::parse(...);
    }

    template<typename it_t>
    auto format(my::wrapper<type_t>& data, basic_format_context<it_t, char_t>& ctx) const -> decltype(ctx.out())
    {
        return my::format(...);
    }
};

// or 

template<typename char_t, typename type_t>
class fmt::formatter<my::wrapper<type_t>, char_t>
{
    my::formatter<type_t, char_t> m_formatter;

public:
    constexpr auto parse(basic_format_parse_context<char_t>& ctx) -> decltype(ctx.begin())
    {
        return m_formatter.parse(...);
    }

    template<typename it_t>
    auto format(my::wrapper<type_t>& data, basic_format_context<it_t, char_t>& ctx) const -> decltype(ctx.out())
    {
        return m_formatter.format(...);
    }
};
и пустить свои иерархии объектов или функций в своём пространстве имен. Я не описываю делали сейчас. Просто указываю на точку кастомизации, из которой всё можно перенести в свой неймспейс и там уже делать кастомизацию или вызывать дефолтные реализации std, если нужно.
Re[4]: Cоздание базового шаблона минуя специализацию
От: rg45 СССР  
Дата: 03.11.22 11:28
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Не совсем. Всё так, но не понятно зачем в глобальном пространстве, когда можно в локальном. Класс диспетчера-то наш и мы вольны вызывать что хотим.


Вызывать что хотим, но по неквалифицированному имени — для того чтобы для UDT вызов выполнялся с использованием ADL. И эти же самые вызовы должны работать и для встроенных типов.

V>Опять не понимаю. Зачем это делать в глобальном пространстве, можно ведь:[ccode]

V>
V>        return my::parse(...);
V>        return my::format(...);
V>


Ну и то, что мы получим, будет не многим лучше того, что мы имеем. ADL при таких вызвах не задествуется. И мы снова заставляем пользователя рвать свои пространства имен для того, чтобы определить функции parse и format в пространстве имен my. Ради этого овчинка выделки не стоит, имхо.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 03.11.2022 12:12 rg45 . Предыдущая версия . Еще …
Отредактировано 03.11.2022 12:09 rg45 . Предыдущая версия .
Отредактировано 03.11.2022 11:33 rg45 . Предыдущая версия .
Отредактировано 03.11.2022 11:32 rg45 . Предыдущая версия .
Re[5]: Cоздание базового шаблона минуя специализацию
От: Videoman Россия https://hts.tv/
Дата: 03.11.22 12:18
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ну и то, что мы получим, будет не многим лучше того, что мы имеем — мы снова заставим пользователя рвать свои пространства имен для того, чтобы определить функции parse и format в пространстве имен my. Ради такого результата овчинка выделки не стоит, имхо.


Я описал просто точку кастомизации. Из нее можно подлезть и сделать как угодно. Я не повторял детали, которые мы до этого тут обсуждали. Можно же сделать и так:
parse(...., my::parse_as<type_t>());
format(...., my::format_as<type_t>());

Тогда ADL начнет работать по полной. Если дашь конкретику чего хочется получить и время, то я постараюсь показать полный код. Или я опять не понял вопроса?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.