Rus*_*hPL 4 c++ templates metaprogramming c++11
我想做的是创建:
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.
}
Run Code Online (Sandbox Code Playgroud)
我一直在用编译时字符串文字分析两个有趣的工作:
编译时间内存对齐的字符串文字
100%constexpr字符串实现
http://sourceforge.net/p/constexprstr/code/HEAD/tree/no-pp-constexpr_string.cpp
基本上我或多或少能够静态地推断格式所需的字符串文字的长度,但仅仅是编译器拒绝将我的工作视为constexpr.另一个大问题是,当使用上述链接中的constexpr字符串时,编译器永远无法推断出结果字符串的大小.
我越努力实现这一点,我的无知就越多,超过了我的热情.我将不胜感激任何解决部分或全部问题的技巧和/或代码示例.
注意:我不是在寻找有关使用不同形式的日志记录的建议,例如通过cout.
注意2:不应该使用任何std :: string,因为它们是运行时
注3:通常所有类型安全的printfs都使用不同的方法,我很熟悉这可以通过多次调用轻松完成printf.我想一次性完成.我也知道缓冲区可以逐步构建,但这个问题是关于构造格式字符串.:)
更新:基本上代码的哪个部分需要实现
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"
Run Code Online (Sandbox Code Playgroud)
很简单,我们将构建一个编译时字符串,其中" %d"包含每个类型的一个或多个,连接一个'\n'并删除前导空格.
首先,我们需要一个类型用作编译时字符串:
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];
Run Code Online (Sandbox Code Playgroud)
为了防止中间步骤生成无意义的缓冲区,一个字符串构建器:
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;};
Run Code Online (Sandbox Code Playgroud)
然后,您需要使用a compile_time_stringbuffer和a类型的函数,并compile_time_stringbuffer使用" %d"或附加的任何内容返回a .由于我们正在处理类型,我甚至不打算定义函数.请注意,我的"结束"专业化会'\n'为您连接一个角色
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...));
Run Code Online (Sandbox Code Playgroud)
最后,一个有用,易于使用的界面.
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;
}
Run Code Online (Sandbox Code Playgroud)
它的使用方式如下:
template<class...Args>
void println(Args...args) {
constexpr const char* formatString = build_compile_time_format_string<Args...>();
std::cout << formatString;
}
Run Code Online (Sandbox Code Playgroud)
以下是执行证明: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() {return str+sizeof...(cs);}
};
Run Code Online (Sandbox Code Playgroud)