在编译时,由一个参数生成两个
From one argument make two - at compile time
我正在编写一个特殊的打印函数,它在编译时生成一个cstdio-printf语句。其思想基本上是,使用可变参数列表调用函数special_print()
,该函数将在编译时组装必要的printf-语句。这是我得到的:
#include <cstdio>
#include <string_view>
// how to implement "expand" from below?
template <typename... Ts>
constexpr const char* cxpr_format = /* ... this one I've already figured out */
template <typename... Ts>
void special_print(Ts... arg)
{
printf(cxpr_format<Ts...>, expand(arg)...);
// should expand to printf("%.*s%d", string_view.size(), string_view.data(), int) with below function call
}
int main()
{
std::string_view strview = "hello world";
int integer = 2;
special_print(strview, integer);
}
我已经找到了创建格式字符串的部分——那是不可能的。但现在问题来了:如果我有一个string_view
作为参数传入,我需要有条件地将其扩展为两个参数来打印:一个用于初始字符指针,另一个用于与%.*s格式说明符一起使用的大小。这才是真正的症结所在。这能在C++中以某种方式完成吗(在编译时(?
注意:在出现任何进一步的问题之前,我想指出,我不知道如何在C++中做到这一点,这是我的问题。每一种方法都会被欣然考虑!
我最初的想法是通过元组转发每个arg,然后"变格应用";在通话中。
template <typename T>
auto expand(T&& t) { return std::forward_as_tuple<T>(t); }
auto expand(std::string_view s) { return std::tuple<int, const char *>(s.size(), s.data()); }
template <typename... Ts>
void special_print(Ts... arg)
{
using expanded = decltype(std::tuple_cat(expand(arg)...));
[]<std::size_t... Is>(auto tup, std::index_sequence<Is...>)
{
printf(cxpr_format<Ts...>, std::forward<std::tuple_element_t<Is, expanded>>(std::get<Is>(tup))...);
}(std::tuple_cat(expand(arg)...), std::make_index_sequence<std::tuple_size_v<expanded>>{});
// should expand to printf("%.*s%d", string_view.size(), string_view.data(), int) with below function call
}
在coliru 上查看
您可以使用std::format
库,而不是使用只知道与C共享的类型的printf
。
struct putchar_iterator {
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = void;
putchar_iterator& operator=(char c) {
eof = (putchar(c) == EOF);
return *this;
}
constexpr putchar_iterator& operator*() { return *this; }
constexpr putchar_iterator& operator++() { return *this; }
constexpr putchar_iterator& operator++(int) { return *this; }
friend bool operator==(putchar_iterator lhs, std::default_sentinel_t) { return lhs.eof; }
private:
bool eof = false;
};
template <typename... Ts>
void special_print(Ts... arg)
{
// You might be able to std::format_to, but I'm not sure
std::vformat_to(putchar_iterator{}, cxpr_format<Ts...>, std::make_format_args(arg...));
}
在godbolt 上查看
相关文章:
- 具有两个间接寻址运算符 (C++) 的函数参数的用途
- 如何允许模板参数中的类类型,仅当它有两个基类时
- C++如果两个模板函数都与参数列表匹配,将调用哪个模板
- 如何从两个不同的函数传递参数
- 两个函数模板候选项.将一个参数作为引用后,选择不太专业的模板
- 命令行参数,cant 或两个变量
- 为什么在传递长整型时调用具有两个双精度类型的参数的重载函数?
- 如何创建两个具有相同名称和不同返回类型并基于布尔参数运行的函数
- 具有两个或多个模板参数的 C++ assigment 运算符
- 检查两个模板参数是否相同
- sscanf() 有两个字符串参数
- 如何在两个树通用的函数中创建一个参数?
- 为什么C++不允许两个同名的函数/类模板,区别仅在于非类型模板参数(整型)的类型?
- 为什么模板参数推导不适用于仅指定前两个参数的可变参数模板类?
- 用相同的参数声明两个构造函数的最偶像化的方法是什么?
- C++如何在 switch 语句中放置两个参数
- 为什么我不能用两个参数重载 C++ 运算符 []?
- 专门处理一个参数(C++模板)的两个模板参数
- C++stoi:这两个重载都无法转换所有参数类型
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)