Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / C++ Новый топик    Ответить
Топик располагается на нескольких страницах: 1 2 3      [все]
 Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
По мотивам статьи вот здесь.

Если коротко, человек написал вариативный шаблон функции, которая есть быть обёрткой вокруг `std::printf()`. Вариативные аргументы шаблона передаются «as is» в `printf()`. Если отбросить нюансы семантики копирования и т.п. Ну...

Вопрос № 1: насколько это соответствует стандарту С++? Они бинарно совместимы?

Идём далее. Пример из его статьи:

template <typename ... Args>
void Print(char const * const format,
           Args const & ... args) noexcept
{
    printf(format, Argument(args)...);
}


Вопрос № 2: в какой последовательности согласно стандарту вызывается функция `Argument()` для вариативных шаблонных параметров? Это определено стандартом или нет?
25 апр 20, 16:19    [22122681]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav
Вопрос № 1: насколько это соответствует стандарту С++? Они бинарно совместимы?

Соответствует.
Бинарная совместимость не требуется. Это два ортогональных механизма.
Распаковка пакета параметров оператором "..." - это просто синтаксический сахар и все работает также как если бы вы аргументы передавали в printf явным перечислением.
petrav
Вопрос № 2: в какой последовательности согласно стандарту вызывается функция `Argument()` для вариативных шаблонных параметров? Это определено стандартом или нет?

Порядок вычисления аргументов неопределен (IIRC, кроме некоторых исключений для перегруженных операторов в свежих версиях стандарта) независимо от того как подставляются аргументы, из вариативного пакета параметров или явным перечислением. А какая разница? Это не влияет на рабочесть примера.
25 апр 20, 19:03    [22122747]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
petrav
Вопрос № 1: насколько это соответствует стандарту С++? Они бинарно совместимы?

Соответствует.
Бинарная совместимость не требуется. Это два ортогональных механизма.
Распаковка пакета параметров оператором "..." - это просто синтаксический сахар и все работает также как если бы вы аргументы передавали в printf явным перечислением.

Окей, я Вас понял.

Anatoly Moskovsky
petrav
Вопрос № 2: в какой последовательности согласно стандарту вызывается функция `Argument()` для вариативных шаблонных параметров? Это определено стандартом или нет?

Порядок вычисления аргументов неопределен (IIRC, кроме некоторых исключений для перегруженных операторов в свежих версиях стандарта) независимо от того как подставляются аргументы, из вариативного пакета параметров или явным перечислением. А какая разница? Это не влияет на рабочесть примера.

А разница **большая**. Я хочу разработать обёртку вокруг `printf()` которая хотя бы на этапе исполнения проверяла строку формата и типы переданных аргументов. Лучше на этапе компиляции.
25 апр 20, 19:19    [22122759]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky,

Для этого мне нужно что бы функция `Argument()` вызывалась последовательно в вышеприведённом примере.
25 апр 20, 19:21    [22122762]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav
А разница **большая**. Я хочу разработать обёртку вокруг `printf()` которая хотя бы на этапе исполнения проверяла строку формата и типы переданных аргументов. Лучше на этапе компиляции.

Для этого мне нужно что бы функция `Argument()` вызывалась последовательно в вышеприведённом примере.

Зачем для этого последовательно вызывать какую-то функцию для каждого аргумента?
25 апр 20, 20:21    [22122794]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
petrav
А разница **большая**. Я хочу разработать обёртку вокруг `printf()` которая хотя бы на этапе исполнения проверяла строку формата и типы переданных аргументов. Лучше на этапе компиляции.

Для этого мне нужно что бы функция `Argument()` вызывалась последовательно в вышеприведённом примере.

Зачем для этого последовательно вызывать какую-то функцию для каждого аргумента?

Ну идея такая. Мы перегружаем функцию `Argument()` для каждого стандартного типа, но одновременно передаём в `Argument()` парсер формата, который в своём состоянии хранит текущий указатель на символ строки формата и мы можем проверить соответствие типа в формате и того, что передано в вариативных шаблонных аргументах.

Для не стандартных типов срабатывает шаблонная перегрузка и там `static_assert`.


Но лучше конечно compile time.

PS: Да, придётся написать свой парсер формата `printf()`, но я думаю это макс на пару дней работы без написания тестов. Т.е. на коленке.
25 апр 20, 20:34    [22122799]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky,

Если у Вас есть какое-то лучшее решение в стиле:

for (auto const &curr: Parametrs)
{
    checkFormat(parser, curr);
}


Так Вы сообщите, плиз. Я не особо изучал С++17.
25 апр 20, 21:09    [22122822]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav,

template <typename ... Args>
bool validate_format(const char* fmt)
{
    // распарсить формат и проверить его соответствие типам Args 
    // например используя рекурсивное применение вспомогательного шаблона к Args
    return ...;
}


template <typename ... Args>
void my_print(const char* fmt, Args ... args)
{
    if (!validate_format<Args...>(fmt))
        throw std::logic_error("invalid format");
    printf(fmt, args...);
}


Это в рантайме.
В компайл-тайме тоже наверно как-то можно, лень думать.
25 апр 20, 22:02    [22122837]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
a guest
Member

Откуда:
Сообщений: 256
petrav
Но лучше конечно compile time.

PS: Да, придётся написать свой парсер формата `printf()`, но я думаю это макс на пару дней работы без написания тестов. Т.е. на коленке.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat-error")
Проверка форматной строки в compile-time готова.
25 апр 20, 22:07    [22122839]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky

Это в рантайме.

Это замечательно, но...

template <typename ... Args>
bool validate_format(const char* fmt)
{
    // распарсить формат и проверить его соответствие типам Args 
    // например используя рекурсивное применение вспомогательного шаблона к Args
    return ...;
}

Я примерно понимаю о чём вы говорите. Наш рекурсивый шаблон зависит от типа первого параметра, он наследуется от самого себя, но предок зависит от типа второго параметра и т.д. Да? Но как это сделать?! Как пронавигировать по Args? Пожалуйста. :)

Anatoly Moskovsky

В компайл-тайме тоже наверно как-то можно, лень думать.

Ну мы тут ни куда же не торопимся. Лень, так лень. Подумаем через неделю.
25 апр 20, 22:19    [22122843]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav,

struct FmtArg
{
    // some type info
};

template <typename T>
bool validate_format_arg(FmtArg& fmt_arg)
{
    // check if T can be used with FmtArg
    return true;
}

// recursion terminator
template <size_t>
bool validate_format_args(std::vector<FmtArg>&)
{
    return true;
}

template <size_t ArgPos, typename T, typename ... Rest>
bool validate_format_args(std::vector<FmtArg>& parsed_fmt)
{
    if (!validate_format_arg<T>(parsed_fmt[ArgPos]))
        return false;
    return validate_format_args<ArgPos + 1, Rest...>;
}

std::vector<FmtArg> parse_format(const char* fmt)
{
    // implement real parse
    std::vector<FmtArg> rv;
    while (auto c = *fmt++) {
        if (c == '%')
            rv.push_back({});
    }
    return rv;
}

template <typename ... Args>
bool validate_format(const char* fmt)
{
    // распарсить формат и проверить его соответствие типам Args
    auto parsed_fmt = parse_format(fmt);
    if (parsed_fmt.size() != sizeof...(Args))
        return false;
    // например используя рекурсивное применение вспомогательного шаблона к Args
    return validate_format_args<0, Args...>(parsed_fmt);
}


template <typename ... Args>
void my_print(const char* fmt, Args ... args)
{
    if (!validate_format<Args...>(fmt))
        throw std::logic_error("invalid format");
    printf(fmt, args...);
}

int main()
{
    my_print("%i %s\n", 2, "a");
    return 0;
}
25 апр 20, 23:48    [22122883]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
petrav,

рекурсивные шаблоны - зло, особенно для компилятора, их место уже занял fold expression

в качестве примера https://www.qt.io/blog/efficient-qstring-concatenation-with-c17-fold-expressions
26 апр 20, 09:38    [22122955]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
Cerebrum
рекурсивные шаблоны - зло, особенно для компилятора, их место уже занял fold expression

Вообще-то fold expr не применим к типам.
Так что пока не добавят в стандарт итерацию по списку типов придется использовать рекурсивные шаблоны.
26 апр 20, 13:38    [22123050]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
В принципе если еще дальше перейти в рантайм, то можно избавиться от рекурсивных шаблонов.

struct FmtArg
{
    // some type info
};

bool compatible_formats(const FmtArg& a, const FmtArg& b)
{
    // check a is compatible with b
    return true;
}

template <typename T>
FmtArg make_format()
{
    // make FmtArg from T
    return FmtArg{};
}

std::vector<FmtArg> parse_format(const char* fmt)
{
    // implement real parse
    std::vector<FmtArg> rv;
    while (auto c = *fmt++) {
        if (c == '%')
            rv.push_back({});
    }
    return rv;
}

template <typename ... Args>
bool validate_format(const char* fmt)
{
    // распарсить формат и проверить его соответствие типам Args
    auto parsed_fmt = parse_format(fmt);
    if (parsed_fmt.size() != sizeof...(Args))
        return false;
    size_t i = 0;
    for (auto& arg_fmt: { make_format<Args>() ... }) {  // тут превращаем типы в значения
        if (!compatible_formats(parsed_fmt[i++], arg_fmt))
            return false;
    }
    return true;
}


template <typename ... Args>
void my_print(const char* fmt, Args ... args)
{
    if (!validate_format<Args...>(fmt))
        throw std::logic_error("invalid format");
    printf(fmt, args...);
}

int main()
{
    my_print("%i %s\n", 2, "a");
    return 0;
}


PS. Правда fold expressions и тут не нужны ))
26 апр 20, 14:00    [22123066]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
mayton
Member

Откуда: loopback
Сообщений: 46599
Какой смысл затаскивать в обсуждение Си? Это - контр-продуктивно вообще.
26 апр 20, 14:00    [22123067]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
Anatoly Moskovsky
Вообще-то fold expr не применим к типам.

прекрасно пременим, если их состав известен (при необходимости может быть расширен за счет добавления нужных специализаций).

я привел пример, в котором производится конкатенация строк, но кто мешает расширить состав обрабатываемых типов, раз уж тут пытаются сэмулировать работу printf, набор типов которой описывается форматной строкой, где каждому типу сопоставлена лексема?

+ Если примера недостаточно, то вот еще один,

в котором автор, перед исполнением ODBC запроса, использует выражения свертки для подготовки буферов переменных (разных типов, состав которых расширяем). В итоге variadic pack разбирается на составляющие и к каждому типу применяется свой собственный обработчик на базе специализированного типом шаблона-функтора
26 апр 20, 15:18    [22123103]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
В принципе если еще дальше перейти в рантайм, то можно избавиться от рекурсивных шаблонов.

Ого... А говорили думать лень. Я правда просил только пример рекурсивного шаблона, но Ваш развёрнутый код очень познавателен. Спасибо!

Но уходить желательно в compile time. Если взять за основу Ваш первый прототип... То имхо, std::vector не нужен. Проходить по строке формата нужно одновременно с навигацией по типам. Оказались в перегрузке для double -- начали искать в строке формата `%f`. Тогда состояние парсера будет описываться одним указателем на char. И, наверное, можно будет сделать compile time.
26 апр 20, 15:21    [22123104]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
mayton
Какой смысл затаскивать в обсуждение Си? Это - контр-продуктивно вообще.

Может printf() кривой, но он очень удобен и производителен. Тут у меня код программный... ему уже лет 30-ть. Тут вообще хардкор нереал. :) Но он работает...
26 апр 20, 15:26    [22123108]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
petrav,

на мой взгляд пройтись по типам в variadic pack'e - вообще не проблема, проблема будет в том, чтобы в компайл тайме обеспечить парсинг фоматной строки, если каждому типу в ней не будет отведено строго обозначенное кол-во символов, чего в реальном printf не было никогда.

Например, тип може быть задан с префиксом указывающем точность округления - %0.5f, и тогда это уже не будет %f для compile-time парсера.

Если же у вас форматная строка всегда четко вида %[type symbol], то можно попробовать в complle time ее разобрать на составляющие (я не пробовал, но если форматная строка - лексема, то думаю, что это реально). А типы сопоставить - это фигня.
26 апр 20, 15:29    [22123111]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Cerebrum
petrav,

на мой взгляд пройтись по типам в variadic pack'e - вообще не проблема, проблема будет в том, чтобы в компайл тайме обеспечить парсинг фоматной строки, если каждому типу в ней не будет отведено строго обозначенное кол-во символов, чего в реальном printf не было никогда.

Например, тип може быть задан с префиксом указывающем точность округления - %0.5f, и тогда это уже не будет %f для compile-time парсера.

Если же у вас форматная строка всегда четко вида %[type symbol], то можно попробовать в complle time ее разобрать на составляющие (я не пробовал, но если форматная строка - лексема, то думаю, что это реально). А типы сопоставить - это фигня.

Нет проблем написать парсер и %f и %0.5f и вообще всех вариантов. Это простой формат, это ж не регулярные выражения. По крайней мере я так думаю.

За ссылки спасибо, прочитаю.

Вот Вы бы написали бы свой прототип? Но не стоит задачи написать свою библиотеку ввода вывода. Нужно создать обёртку вокруг printf().

Сообщение было отредактировано: 26 апр 20, 15:37
26 апр 20, 15:37    [22123116]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
mayton
Какой смысл затаскивать в обсуждение Си? Это - контр-продуктивно вообще.

Ещё меня привлекает идея расширить стандартный формат:
std::printf("%5.3ang", angle); // Тут автоматически перевод радиан в углы.

Конечно, перед передачей в оригинальный printf() нужно и строку формата подкорректировать до стандартной. Но это уже в run time, конечно.
26 апр 20, 15:59    [22123124]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
mayton
Member

Откуда: loopback
Сообщений: 46599
Я думаю что тебе нужна Scala и ее implicit conversions.
Ты - постигнешь дзен и твоя душа придёт в состояние гармонии.
26 апр 20, 16:51    [22123145]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Очередной этап изысканий.

Cerebrum

Например, тип може быть задан с префиксом указывающем точность округления - %0.5f, и тогда это уже не будет %f для compile-time парсера.


Вроде работает. Есть конечно вероятность, что в определённый момент компилятор не выдержит сложности парсера. И я не уверен, что третий тестовый формат правильный. Но такой вариант вообще запретить нужно. Сузить стандартный формат, а потом расширить нестандартными форматами -- до задач предметной области.

constexpr bool checkCharOrNo(char const *&frmt, char const ch)
{
    if (*frmt == ch)
    {
        ++frmt;
        return true;
    }
    return false;
}

constexpr bool checkDigitOrNo(char const *&frmt)
{
    while (*frmt >= '0' && *frmt <= '9')
    {
        ++frmt;
    }
    return true;
}

constexpr bool checkFloat(char const *frmt)
{
    while (*frmt != '\0')
    {
        if (checkCharOrNo(frmt, '%'))
        {
            checkDigitOrNo(frmt);
            if (checkCharOrNo(frmt, '.'))
            {
                checkDigitOrNo(frmt);
            }
            return *frmt == 'f';
        }
        ++frmt;
    }
    return false;
}

static_assert(checkFloat("Angle: %f."));
static_assert(checkFloat("Angle: %10f."));
static_assert(checkFloat("Angle: %10.f.")); // Запретить в своём парсере.
static_assert(checkFloat("Angle: %10.3f."));
26 апр 20, 16:56    [22123153]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
Cerebrum
прекрасно пременим, если их состав известен (при необходимости может быть расширен за счет добавления нужных специализаций).

Не применим. Потому что в С++ нет бинарных операторов применимых к типам. А fold expression это применение операторов к списку сущностей. И поскольку есть только операторы применимые к значениям, то fold expression возможен только для пакета параметров, но не пакета типов этих параметров.
26 апр 20, 19:05    [22123220]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Господа, нам осталось решить одну проблему: как в одном вызове совместить и статическую проверку данных и динамическую печать данных? Желательно найти выход без макросов. Неужели выхода нет?! :-((( Вот псевдокод, он не компилируется:

constexpr bool check(char const *str)
{
    return str != nullptr;
}

constexpr void print_f(char const *str)
{
    static_assert(check(str)); // Compile time.
    std::printf(str);          // Run time.
}

А вот жуткое решение на вариативных макросах:

#if (DEBUG)
#define print_f(format, ...)                       \
    static_assert(checkArgs(format, __VA_ARGS__)); \
    printStr(format, __VA_ARGS__);
#elif (RELEASE)
// В Release хотим компилироваться без макросов. Для очистки совести.
#endif

template <size_t Size, typename... Parameters>
constexpr bool checkArgs(char const (&format)[Size],
                         Parameters const &... parameters)
{
    // В прототипе проверим длину формата и наличие нуля.
    char const *end = format;
    while (*end++ != '\0');
    size_t const len = end - format - 1;
    return len>0 && len<128;
}

// Тут начинается тихий ужас. В зависимости от конфигурации имя функции печати
// должно быть разным.
template <size_t Size, typename... Parameters>
constexpr void
#if (DEBUG)
printStr
#else
print_f
#endif
(char const (&format)[Size], Parameters const &... parameters)
{
    if (!checkArgs(format, parameters...)) throw -1; // Для Release.
    std::snprintf(buff, std::size(buff), format, parameters...);
}

void newTest()
{
    print_f("Angle: %0.3f. Mode: %s.", 12.8, "Prepare");
}


Заранее спасибо!
1 май 20, 09:17    [22126073]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
petrav,

уже говорил и скажу еще раз, для тех кто в танке - юзай fold expression
моя идея представлена ниже (это только набросок, но он вполне пригоден для ее понимания и даже компилируется, проверил)
дальше доводить ее до ума придется тебе самому

#include <array>

template <size_t N>
using static_string = std::array<const char, N>;

template <size_t N, size_t ...Indexes>
constexpr static_string<N> make_static_string(const char (&str)[N], std::index_sequence<Indexes...>)
{
	return {str[Indexes] ..., '\0'};
}

template <size_t N, typename Indexes = std::make_index_sequence<N - 1>>
constexpr static_string<N> make_static_string(const char (&str)[N])
{
	return make_static_string(str, Indexes{});
}

template <typename T>
struct type_processor;

template <>
struct type_processor<float>
{
	template <size_t N>
	constexpr explicit type_processor(const static_string<N>& fmt, float fValue, char** ppOutBuff) : value(fValue), pp_out_buff(ppOutBuff)
	{
		// я не знаю (нет ни времени ни желания разбираться) как сделать проверку типа в форматной строке в compile time
		// после проверки форматная строка должна быть смещена на X позиций, чтобы следующая итерация проверяла следующий
		// тип в форматной строке

		static_assert(N >= 2 /*&& fmt[0] == '%' && fmt[1] == 'f'*/);
	}

	constexpr bool operator ()(void)
	{
		// TODO: конвертируем value в строку и записываем в pp_out_buff 
		
		// смещаем указатель pp_out_buff за блок записанных данных
		return true;
	}

	char**	pp_out_buff;
	float	value;
};

template <>
struct type_processor<int>
{
	template <size_t N>
	constexpr explicit type_processor(const static_string<N>& fmt, int nValue, char** ppOutBuff) :	value(nValue), pp_out_buff(ppOutBuff)
	{
		static_assert(N >= 2 /*&& fmt[0] == '%' && fmt[1] == 'f' && ppOutBuff != nullptr*/);
	}

	constexpr bool operator ()(void) 
	{
		// TODO: конвертируем value в строку и записываем в pp_out_buff
		
		// смещаем указатель pp_out_buff за блок записанных данных;
		return true;
	}

	char**	pp_out_buff;
	int		value;
};

template <>
struct type_processor<const char*>
{
	template <size_t N>
	constexpr explicit type_processor(const static_string<N>& fmt, const char* pValue, char** ppOutBuff) :	value(pValue), pp_out_buff(ppOutBuff)
	{
		static_assert(N >= 2 /*&& fmt[0] == '%' && fmt[1] == 'f' && ppOutBuff != nullptr*/);
	}

	constexpr bool operator ()(void) 
	{
		// TODO: копируем value в pp_out_buff 
		
		// смещаем указатель pp_out_buff за блок записанных данных
		return true;
	}

	char**		pp_out_buff;
	const char*	value;
};

template <size_t N, typename ...ArgsT>
constexpr bool my_printf(const static_string<N>& fmt, ArgsT ...vArgs)
{
	// TODO: организовать автоматический рассчет буфера под результирующую строку
	// 
	size_t szLength = 0;
	// (type_processor<ArgsT>(fmt, vArgs, (char**)&outBuff).calculate_size(szLength) && ...);

	char outBuff[256] = {0};
	return (type_processor<ArgsT>(fmt, vArgs, (char**)&outBuff)() && ...);
}

int main()
{
	constexpr auto fmt = make_static_string("%f %d %s");
	my_printf(fmt, 0.56f, 10, "some string");
	return 0;
}

если ты попробуешь передать в my_printf значение неизвестного type_processor типа, то на этапе компиляции уже получишь ор. Добавив специализаций type_processor можно покрыть все стандартные типы, которые должна жрать и преобразовывать к строке my_printf, таким образом, можно расширять набор ее типов по мере необходимости. Все что не входит в этот круг - идет лесом на этапе компиляции. Сможешь сделать static_assert проверку куска форматной строки на соответствие типу type_process - будешь молодец!

Одна из больших проблем (опять же, как я говорил ранее) - нерегулярность форматной строки. В моем примере все типы четко фиксируемые двумя символами %[symbol]. Как проанализировать форматную строку в компайл тайме с нерегулярной структурой я хз, но кто-то говорил выше, что это - ерунда, ну, тогда я уверен, все у вас получится

Вторая большая проблема - размер буфера под выходные данные. В своем примере его задал статически, но если получится все что написано выше, то размер можно посчитать таким же макаром через fold expression. Это можно сделать в тех же type_expression специализациях, добавив в них функции calculate_size или переопределив оператор ().

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

может это https://habr.com/ru/post/428846/
еще поможет или натолкнет на какие-то мысли по анализу форматной строки в compile time

PS. я не стал заморачиваться с std::decay_t, но тебе придется

Сообщение было отредактировано: 1 май 20, 13:25
1 май 20, 13:26    [22126179]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
Cerebrum,

return (type_processor<ArgsT>(fmt, vArgs, (char**)&outBuff)() && ...);

Ну и где здесь fold-expression над типом? )))
1 май 20, 13:45    [22126190]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav
Господа, нам осталось решить одну проблему: как в одном вызове совместить и статическую проверку данных и динамическую печать данных? Желательно найти выход без макросов. Неужели выхода нет?! :-((( Вот псевдокод, он не компилируется:


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

Сообщение было отредактировано: 1 май 20, 13:56
1 май 20, 13:57    [22126196]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
Anatoly Moskovsky
Ну и где здесь fold-expression над типом? )))

в type_processor'e
специализация выбирается на основе типа, нет специализации - нет компиляции.

ясен пень, что fold expression не сделает цепочку типов, это и не подразумевалось,
странно, что приходится это объяснять, в особенности после того, как я привел аж два примера иллюстрирующих мое высказывание

Сообщение было отредактировано: 1 май 20, 14:17
1 май 20, 14:16    [22126211]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
Cerebrum
ясен пень, что fold expression не сделает цепочку типов, это и не подразумевалось,
странно, что приходится это объяснять, в особенности после того, как я привел аж два примера иллюстрирующих мое высказывание

Начнем с того что fold было приведено как замена рекурсивной обработки списка типов в компайл-тайм.
При этом все примеры работают не с типами и не в компайл-тайм.
Если мы вместо типов работаем со значениями, то все что тут делает fold можно сделать и обычным циклом )))
1 май 20, 14:32    [22126219]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Cerebrum
petrav,

уже говорил и скажу еще раз, для тех кто в танке - юзай fold expression
моя идея представлена ниже (это только набросок, но он вполне пригоден для ее понимания и даже компилируется, проверил)
дальше доводить ее до ума придется тебе самому

Спасибо за код. :) На уровне концепции я его понял. Но он не будет работать в compile time. И Вы делаете немного не то что Вас просят. :)

Строку формата в стиле "%21.567f" я уже разбирал compile-time выше в этой ветке. Только что я написал рекурсивный обход по типам тоже compile time. Осталось совместить.

И погуглить как строку формата сделать аргументом шаблона.
1 май 20, 16:40    [22126282]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Cerebrum

в type_processor'e
специализация выбирается на основе типа, нет специализации - нет компиляции.

Кстати! В Вашем коде есть очень большой изъян. Нет специализации, но есть приведение типов! Именно поэтому у вас получилось написать специализацию для const char *, хотя в Вашем примере аргумент "some string" -- это не const char * ! Это массив. Вот Ваш тестовый код:

my_printf(fmt, 0.56f, 10, "some string");


Т.е. Вы с таким подходом можете написать специализацию для double, но забыть специализацию для char. И Ваш код, при передаче char, будет компилироваться, но не будет проверять соответствие типов аргументов и строки формата. Даже в run time! Мне так кажется.

Т.е. правильно говорит Anatoly Moskovsky, Вы работаете не с типами. Вы работаете со значениями.

Вот мне пришлось помучится что бы написать специализацию для аргумента (не формата) в стиле "some string". Потому что эти рекурсивные шаблоны чётко руководствуются типом, а не значением.
1 май 20, 19:17    [22126341]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
petrav
Вот мне пришлось помучится что бы написать специализацию для аргумента (не формата) в стиле "some string"

Cerebrum
PS. я не стал заморачиваться с std::decay_t, но тебе придется

откуда вы только беретесь такие со своим Московским...

Модератор: Вложение удалено.


Модератор: Вложение удалено.


Сообщение было отредактировано: 2 май 20, 09:01
1 май 20, 19:34    [22126348]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Cerebrum
petrav
Вот мне пришлось помучится что бы написать специализацию для аргумента (не формата) в стиле "some string"

Cerebrum
PS. я не стал заморачиваться с std::decay_t, но тебе придется

откуда вы только беретесь такие со своим Московским...

Так я и не утверждаю, что разбираюсь в С++17. Но не очень понятно, что будет в Вашем примере, если мы определим перегрузку (явную специализацию шаблона) только для double, подставим %12f в виде формата, подставим char в runtime как аргумент, а потом всё это передадим в snprintf(). Передача в snprintf() это требование.

И причём тут std::decay...
1 май 20, 20:23    [22126371]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Cerebrum
petrav
Вот мне пришлось помучится что бы написать специализацию для аргумента (не формата) в стиле "some string"

Cerebrum
PS. я не стал заморачиваться с std::decay_t, но тебе придется

откуда вы только беретесь такие со своим Московским...

Мне кажется, Вы задействовали механизм преобразования типов аргументов. А по ТЗ нужно однозначно и чётко проверить соответствие типов аргументов и строки формата. В compile time. Ну или хотя бы в run time, но однозначно.
1 май 20, 20:52    [22126378]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav
И Вы делаете немного не то что Вас просят. :)

Ну так всегда бывает, когда узнал новую фичу, и теперь суешь ее везде без разбору )))
1 май 20, 20:53    [22126379]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav
И причём тут std::decay...

std::decay автоматически выведет тип указателя из типа строкового литерала (без явного указания типов)

Сообщение было отредактировано: 1 май 20, 20:58
1 май 20, 20:55    [22126380]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
petrav
И причём тут std::decay...

std::decay автоматически выведет тип указателя из типа строкового литерала (без явного указания типов)

Да, я это понял... со второго раза, правда. Но лучше поздно, чем... Я думаю "std::decay" тут ненужен. Он сносит дополнительную информацию с типов, а это ни к чему, мы всё проверим compile time. Я тут проще и надёжнее вещь спрограммировал. И Вы знаете, все "static_assert" работают, достаточно инвертировать условие -- и тут же код перестаёт собираться. Если аргумент "12.8" переделать на "12.8F", то код тоже перестаёт собираться. Т.е. корректность максимальная.

Вот тестовый код:

void newTest()
{
    double d = std::rand();
    char* s = "Jim";

    bool const res1 =
        print_f("Angle: %0.3f. Mode: %s. Name: %s.", d, "Prepare", s);
    bool const res2 =
        print_f("My float: %f.", 12.8);
    bool const res3 =
        print_f("Hello, world !");
}


А вот код обхода типов compile time, основанный на Вашем примере.

template <size_t N>
constexpr void processArray(char const (&)[N])
{
    static_assert(N > 0); // Я знаю, что массив не может быть размера ноль.
}

template <typename T>
constexpr void processType()
{
    // Для аргументов типов "строковый литерал".
    static_assert(std::is_array_v<T>);
    // А вот тут уже значения, а не типы, но приведение типов не работает с
    // массивами. Ну, наверное, не работает. Скорее всего…
    processArray(T{});
}

template <>
constexpr void processType<char *>()
{
}

template <>
constexpr void processType<double>()
{
}

template <size_t N>
constexpr void validateFormatArgs()
{
    static_assert(N == 0);
}

template <size_t N, typename T, typename... Rest>
constexpr void validateFormatArgs()
{
    processType<T>();
    validateFormatArgs<N-1, Rest...>();
}

template <size_t Size, typename... Parameters>
constexpr bool checkArgs(char const (&format)[Size],
                         Parameters const &... parameters)
{
    // Compile time навигация по типам.
    validateFormatArgs<sizeof...(Parameters), Parameters...>();
}
2 май 20, 19:33    [22126748]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
a guest
Member

Откуда:
Сообщений: 256
petrav
Если аргумент "12.8" переделать на "12.8F", то код тоже перестаёт собираться. Т.е. корректность максимальная.
В каком смысле «максимальная корректность», если
printf("My float: %f.", 12.8f);
это ОК?
3 май 20, 21:53    [22127008]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
a guest
petrav
Если аргумент "12.8" переделать на "12.8F", то код тоже перестаёт собираться. Т.е. корректность максимальная.
В каком смысле «максимальная корректность», если
printf("My float: %f.", 12.8f);
это ОК?

В каком смысле ОК? В плане стандарта C++, да ОК. В плане однозначной проверки типов -- супер ОК. Не написана специализация для "float" и выключено приведение типов. Компиляция ломается. Это Супер ОК. Только что написал специализацию для "float" -- тут же начало компилироваться.

Или Вы про различие "%f", "%lf" и "%Lf" ?
3 май 20, 22:29    [22127018]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
a guest
Member

Откуда:
Сообщений: 256
petrav
a guest
пропущено...
В каком смысле «максимальная корректность», если
printf("My float: %f.", 12.8f);
это ОК?

В каком смысле ОК?
В том смысле, что это корректное использование printf.
Просто странно читать про «максимальную корректность» чекера аргументов, который должен разрешать всё то, что допустимо для обычного printf, а он отказывается компилировать.
3 май 20, 23:45    [22127032]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
a guest
petrav
пропущено...

В каком смысле ОК?
В том смысле, что это корректное использование printf.

Под «максимальной корректностью» имелась в виду возможность однозначно в compile time детектировать тип аргумента. И запретить приведение типов. Т.е. под корректностью имелась возможность чётко увидеть тип. И никаких "std::decay".

a guest
Просто странно читать про «максимальную корректность» чекера аргументов, который должен разрешать всё то, что допустимо для обычного printf, а он отказывается компилировать.

Нет… Чекер, наоборот должен запрещать всякие бессмысленные изыски. Зачем "%d", если есть "%i" ? На сайте cppreference написано, что "%f" и "%lf" эквивалентны. А `%Lf` -- это "long double", которая с 2005-го года не 80-т бит, а соответствует "double". Кстати, зачем нам аргументы типа "float" ? Да по-запрещать всё к чертям. Я такие бардаки годами разбираю. И везде какие-то глюки и косяки.

Нам нужно сузить формат, а потом расширить его на печать, например, углов. С авто. преобразованием радиан в углы. И это тоже уменьшит количество косяков.
4 май 20, 00:38    [22127049]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50076

А может, всё-таки проще компилятор сменить? Что вы так к убогой студии привязались?..

Posted via ActualForum NNTP Server 1.5

4 май 20, 00:53    [22127050]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
Dimitry Sibiryakov
А может, всё-таки проще компилятор сменить? Что вы так к убогой студии привязались?..

Я так понял что помимо printf надо будет реализовать нестандартные форматы, и смена компилятора тут не поможет.
4 май 20, 01:02    [22127051]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
mayton
Member

Откуда: loopback
Сообщений: 46599
Да все претензии по форматной печати можно адресовать к конкретной библиотеке. Вот ее и ругайте.

Компиллятор-то тут причем?
4 май 20, 10:12    [22127101]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Dimitry Sibiryakov

А может, всё-таки проще компилятор сменить? Что вы так к убогой студии привязались?..

Студия прекрасна. Я почитал документацию, да хорошая штука:

void my_printf(int x, int y, char const *format, ...)
    __attribute__((format(printf, 3, 4)));

void my_printf(int x, int y, char const *format, ...)
{
}


В Студии есть аналогичный атрибут: _Printf_format_string_. И там ещё куча атрибутов, другое дело что активация этого анализатора кода у меня сборку проекта замедляет в шесть раз. И начинают лезть предупреждения на сторонние библиотеки. Не знаю что делать с этим.
4 май 20, 11:22    [22127143]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
Dimitry Sibiryakov
А может, всё-таки проще компилятор сменить? Что вы так к убогой студии привязались?..

Я так понял что помимо printf надо будет реализовать нестандартные форматы, и смена компилятора тут не поможет.

Да... вот только...

// Можно было бы написать так с преобразованием радиан в углы.
print_f("%ang", 0.3);
// Но зачем это делать если можно написать так?
std::printf("%f", toAng(0.3));
// В обоих случаях нужно явно указать, что в данных радианы.

Собственная compile time проверка формата с преобразованием значений в run time имела бы смысл в таких случаях:

Angle<double, AngType::Radian> ang = {};
double angles[3] = {};
std::string str;
print_f("%ang %ang_arr %s", ang, angles, str);

Смутные сомнения об overengineering меня, конечно, терзали с самого начала...

Сообщение было отредактировано: 4 май 20, 12:29
4 май 20, 12:29    [22127179]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
petrav
Смутные сомнения об overengineering меня, конечно, терзали с самого начала...

на мой взгляд для type rich кода следует использовать operator "" с собственными суффиксами для типов и перегрузку operator <<, а не измываться над printf, который уже много раз предавали анафеме
4 май 20, 12:49    [22127188]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Cerebrum
Member

Откуда: Омикрон Персей 8
Сообщений: 7937
Cerebrum
petrav
Смутные сомнения об overengineering меня, конечно, терзали с самого начала...

на мой взгляд для type rich кода следует использовать operator "" с собственными суффиксами для типов и перегрузку operator <<, а не измываться над printf, который уже много раз предавали анафеме
тогда никаких проблем с разделением углов в радианах от углов в градусах не будет
4 май 20, 12:50    [22127189]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Cerebrum
petrav
Смутные сомнения об overengineering меня, конечно, терзали с самого начала...

на мой взгляд для type rich кода следует использовать operator "" с собственными суффиксами для типов и перегрузку operator <<, а не измываться над printf, который уже много раз предавали анафеме

Вы имеете в виду операторы в стиле "123.4_rad" ? Да, штука хорошая, но это уже про написание литералов, а не про печать данных.

Вообще, анафеме нужно предать библиотеку <iostream>. Совершено непонятно о чём думали люди которые это проектировали. Ведь были же все языковые инструменты, что бы разработать type safe форматирование строк в стиле "printf()" -- как это сделали в "QString" и "boost::format", например.

Впрочем, C++ это язык для создания велосипедов и костылей. Может они неосознанно так проектировали <iostream>, что бы пользователей спровоцировать к творчеству через шок. Кстати, Страуструп, собственно, и писал, что C++ проектируется так, что бы пользователи могли расширять язык своими типами. Видимо многоуважаемый Бьёрн передал эту мысль другим проектантам и они накосячили не осознанно.

А может и осознанно...
4 май 20, 16:48    [22127281]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
Anatoly Moskovsky
Member

Откуда: Odessa
Сообщений: 6494
petrav,

Посмотрите еще на тему форматирования

1 https://en.cppreference.com/w/cpp/utility/format
2 https://github.com/fmtlib/fmt (в т.ч. имплементация std::format)
3 https://github.com/mpark/format
4 май 20, 21:43    [22127403]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
petrav,

Посмотрите еще на тему форматирования

1 https://en.cppreference.com/w/cpp/utility/format
2 https://github.com/fmtlib/fmt (в т.ч. имплементация std::format)
3 https://github.com/mpark/format

Спасибо, завтра начну изучать. Кстати, я тут нашёл простейший приём, который решает все проблемы:

int printf_wrapper_(const char *format, ...);

#define printf_wrapper(...) \
(false || printf(__VA_ARGS__), printf_wrapper_(__VA_ARGS__))

Просто и ясно. Студия тут же начинает выдавать предупреждения о неправильности формата и аргуменов. Правда тут же ломается перегрузка по теме printf()/wprintf().
5 май 20, 19:14    [22127785]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
petrav

int printf_wrapper_(const char *format, ...);

#define printf_wrapper(...) \
(false || printf(__VA_ARGS__), printf_wrapper_(__VA_ARGS__))

Просто и ясно. Студия тут же начинает выдавать предупреждения о неправильности формата и аргуменов. Правда тут же ломается перегрузка по теме printf()/wprintf().

Кстати, вот я уверен, что на таком коде PVS Studio сейчас в позу встанет и начнёт сыпать предупреждениями.

Что ещё нужно сделать, что бы просто начать программировать на C++, а не прорываться сквозь строй косяков?
5 май 20, 21:10    [22127834]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
petrav,

Посмотрите еще на тему форматирования

1 https://en.cppreference.com/w/cpp/utility/format

Пока Студия 2019 не поддерживает C++ 20.

Anatoly Moskovsky
2 https://github.com/fmtlib/fmt (в т.ч. имплементация std::format)

В этой библиотеке compile time check не работает как нужно. Что-то проверяет, но вот это компилируется, хотя оно и неверно:

std::string s = fmt::format(FMT_STRING("Hello, {0}!"), "world", 1.1);

Я уж не говорю о том, что "FMT_STRING" -- это макрос.

Anatoly Moskovsky
3 https://github.com/mpark/format

Библиотека уже три года не поддерживается, не думаю что там есть какое-то откровение.
6 май 20, 11:25    [22128031]     Ответить | Цитировать Сообщить модератору
 Re: Вариативные шаблоны C++ и вариативные функции Си  [new]
petrav
Member

Откуда:
Сообщений: 2118
Anatoly Moskovsky
petrav
Господа, нам осталось решить одну проблему: как в одном вызове совместить и статическую проверку данных и динамическую печать данных? Желательно найти выход без макросов. Неужели выхода нет?! :-((( Вот псевдокод, он не компилируется:


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

Это я понимаю, но как же строку передать как аргумент шаблона? Гуглинг не помог, есть решения в стиле Boost.MPL, но там такие костыли и жесть нереальная. Ну и макросы. Я не думаю, что это хороший дизайн. Т.е. резко превышен болевой порог в плане костылизма.

Если явно строку не поместить как глобальную константу, то, видимо, её и нельзя передать как аргумент шаблона. По крайней мере по человечески. В принципе можно отступить от стандартного printf() style. Например так:

my_print_f<fmt("%f")>(1.2);

Но я думаю это невозможно.

Если Вы забыли, напомню. Предлагается что бы заработал такой код:
constexpr bool check(char const *str)
{
    return str != nullptr;
}

constexpr void print_f(char const *str)
{
    static_assert(check(str)); // Compile time.
    std::printf(str);          // Run time.
}
6 май 20, 17:18    [22128341]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: 1 2 3      [все]
Все форумы / C++ Ответить