C ++ 11编译时间格式字符串文字构造调用printf [英] C++11 compile time format string literal construction for invoking printf

查看:224
本文介绍了C ++ 11编译时间格式字符串文字构造调用printf的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做的是创建:

  template< Args ... args)> 
int println(Args ...){
//调用的实现:
// printf(< string literal format string at compile time>,args ...);
//额外的perk将是编译时类型检查
//我希望通过一些模板
//特殊化为每个类型提供一个格式化字符串。
}

我一直在分析编译时字符串文字的两个有趣的工作: / p>



基本上我或多或少能够静态推断格式所需的字符串文本的长度,但没有更多的编译器拒绝将我的工作作为constexpr。另一个大问题是当从上面的链接使用constexpr字符串时,编译器永远不能推断出结果字符串的大小。



越多我试图实现这更多我的无知超过了我的热情。我会感谢任何提示和/或代码示例,解决执行这样的实现的一些或所有的问题。



注意:我不是寻求关于使用不同的建议



注意2:不应使用任何std :: string作为运行时



注意:通常所有的类型安全的printfs都使用不同的方法,我很熟悉这可以很容易地做多个调用 printf 。我想在一个单一的电话。我也知道缓冲区可以递增地构建,但这个问题是关于构造格式字符串。 :)



更新:基本上代码需要实现的部分是

  constexpr const char * formatString = build_compile_time_format_string(args ...); 
// build_compile_time_format_string(3,hi,-3.4)
//应评估为%d%s%f
//或到%d hi%f


解决方案

很简单,我们将构建一个编译时字符串a %d或者对于每种类型,连接一个'\\\
'



开始时,我们需要一个类型作为编译时字符串:

  template< char ... cs> struct compile_time_string 
{static constexpr char str [sizeof ...(cs)+1] = {cs ...,'\0'};};
template< char ... cs>
const char compile_time_string< cs ...> :: str [sizeof ...(cs)+1];

并且为了防止中间步骤生成无意义的缓冲区,字符串构建器:

 模板< char ... cs> struct compile_time_stringbuilder 
{typedef compile_time_string< cs ...>串;};

//从stringbuilder中删除前导空格
template< char ... cs> struct compile_time_stringbuilder<'',cs ...>
{typedef typename compile_time_stringbuilder< cs ...> :: string string;};

然后,你需要一个 compile_time_stringbuffer 和一个类型,并返回一个 compile_time_stringbuffer %d或任何附加。因为我们处理类型,我甚至不打扰定义函数。请注意,我的结束专业化为您连接'\\\
'
字符

  template< char ... cs,class ... Ts> 
compile_time_stringbuilder< cs ...,'\\\
'> concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...>);

template< char ... cs,class ... Ts>
auto concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...>,int,Ts ... args)
- > decltype(concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...,'','%','d'>(),args ...)

template< char ... cs,class ... Ts>
auto concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...>,const char *,Ts ... args)
- > decltype(concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...,'','%','s'>(),args ...)

template< char ... cs,class ... Ts>
auto concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...>,double,Ts ... args)
- > decltype(concatenate_compile_time_format_string(compile_time_stringbuilder< cs ...,'','%','f'>(),args ...)

最后,一个有用,易于使用的界面。

  template< class ... Ts> 
constexpr const char * build_compile_time_format_string()
{
using compile_time_stringbuilder = decltype(concatenate_compile_time_format_string(compile_time_stringbuilder<>(),std :: declval< Ts>()...)
using compile_time_string = typename compile_time_stringbuilder :: string;
return compile_time_string :: str;
}

它的用法如下:

  template< class ... Args> 
void println(Args ... args){
constexpr const char * formatString = build_compile_time_format_string< Args ...>();
std :: cout<< formatString;
}

这里是执行的证明: http://coliru.stacked-crooked.com/a/16dc0becd3391aaa






完全不必要的,把 compile_time_string 彻底匹配 const std: :string ,沿着这些行:

  template< char ... cs> struct compile_time_string 
{
static constexpr char str [sizeof ...(cs)+1] = {cs ...,'\0'};
constexpr size_t size(){return sizeof ...(cs);}
constexpr char * begin(){return str;}
constexpr char * end ...(cs);}
};


What I would like to do is to create:

template<Args... args)>
int println(Args...) {
  // implementation which calls:
  // printf("<string literal format string at compile time>", args...);
  // additional perk would be compile time type checking
  // I expect to provide a format string for each type by some template
  // specialization.
}

I have been analyzing two interesting pieces of work with compile time string literals:

Basically I am more or less able to statically infer length of required string literal for format but nothing more as compiler refuses to treat my work as constexpr. Another big problem is when using constexpr strings from the above link the compiler is never able to infer the size of the resulting string.

The more I try to achieve this the more my ignorance outweighs my enthusiasm. I would appreciate any tips and/or code samples that solve some or all of the problems with doing such an implementation.

Note: I am not looking for advice regarding using different forms of logging such as through cout.

Note2: The should not use any std::string as those are runtime

Note3: Generally all the type-safe printfs are using different approaches and I am familar that this could be easily done with multiple calls to printf. I would like to do it in a single call. I also know that the buffer could be incrementally built but this question is about constructing the format string. :)

Update: Basically what part of the code needs to achieve is

constexpr const char* formatString = build_compile_time_format_string(args...);
// build_compile_time_format_string(3, "hi", -3.4)
//     should evaluate to "%d %s %f"
//          or to "%d hi %f"

解决方案

Simple enough, we'll build a compile time string with a " %d" or whever for each type, concatenate a '\n', and strip the leading space.

To start, we needed a type to use as a compile time string:

template<char...cs> struct compile_time_string 
{static constexpr char str[sizeof...(cs)+1] = {cs...,'\0'};};
template<char...cs>
const char compile_time_string<cs...>::str[sizeof...(cs)+1];

And to prevent intermediate steps from generating pointless buffers, a stringbuilder:

template<char...cs> struct compile_time_stringbuilder 
{typedef compile_time_string<cs...> string;};

//remove leading spaces from stringbuilder
template<char...cs> struct compile_time_stringbuilder<' ', cs...>
{typedef typename compile_time_stringbuilder<cs...>::string string;};

Then, you need functions that take a compile_time_stringbuffer and a type, and return a compile_time_stringbuffer with the " %d" or whatever appended. Since we're dealing with types, I don't even bother defining the functions. Note that my "end" specialization concatenates a '\n' character for you

template<char...cs, class...Ts> 
compile_time_stringbuilder<cs...,'\n'> concatenate_compile_time_format_string(compile_time_stringbuilder<cs...>);

template<char...cs, class...Ts> 
auto concatenate_compile_time_format_string(compile_time_stringbuilder<cs...>,int,Ts...args)
-> decltype(concatenate_compile_time_format_string(compile_time_stringbuilder<cs...,' ','%','d'>(),args...));

template<char...cs, class...Ts> 
auto concatenate_compile_time_format_string(compile_time_stringbuilder<cs...>,const char*,Ts...args)
-> decltype(concatenate_compile_time_format_string(compile_time_stringbuilder<cs...,' ','%','s'>(),args...));

template<char...cs, class...Ts> 
auto concatenate_compile_time_format_string(compile_time_stringbuilder<cs...>,double,Ts...args)
-> decltype(concatenate_compile_time_format_string(compile_time_stringbuilder<cs...,' ','%','f'>(),args...));

Finally, a helpful, easy to use interface.

template<class...Ts>
constexpr const char* build_compile_time_format_string()
{
    using compile_time_stringbuilder = decltype(concatenate_compile_time_format_string(compile_time_stringbuilder<>(),std::declval<Ts>()...));
    using compile_time_string = typename compile_time_stringbuilder::string;
    return compile_time_string::str;
}

And it's used like so:

template<class...Args>
void println(Args...args) {
    constexpr const char* formatString = build_compile_time_format_string<Args...>();
    std::cout << formatString;
}

Here's proof of execution: http://coliru.stacked-crooked.com/a/16dc0becd3391aaa


Completely unnecessarily, it might be fun to flesh out compile_time_string to roughly match the interface of const std::string, along these lines:

template<char...cs> struct compile_time_string 
{
    static constexpr char str[sizeof...(cs)+1] = {cs...,'\0'};
    constexpr size_t size() {return sizeof...(cs);}
    constexpr char* begin() {return str;}
    constexpr char* end() {return str+sizeof...(cs);}
};

这篇关于C ++ 11编译时间格式字符串文字构造调用printf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆