ahm*_*ikh 0 c++ templates type-traits template-meta-programming c++11
我的任务有问题.转让的问题如下:
编写一个名为Interpolate的函数模板,它将使下面的工作成为可能.当格式字符串中遇到相应的%时,将输出每个参数.所有输出应该最终使用适当的重载<<运算符完成.\%序列应输出百分号.
SomeArbitraryClass obj;
int i = 1234;
double x = 3.14;
std::string str("foo");
std::cout << Interpolate(R"(i=%, x1=%, x2=%\%, str1=%, str2=%, obj=%)", i, x, 1.001, str, "hello", obj) << std::endl;
Run Code Online (Sandbox Code Playgroud)
如果百分号的数量与输出的参数数量不匹配,则抛出类型为cs540 :: WrongNumberOfArgs的异常.
现在,我已经开始编写代码以使其工作.但是,我遇到了使用非POD的问题.这是我到目前为止所写的内容:
#include <iostream>
#include <sstream>
#include <string>
#include <type_traits>
std::string Interpolate(std::string raw_string) {
std::size_t found = raw_string.find_first_of("%");
if(found != std::string::npos && raw_string[found-1] != '\\') {
std::cout << "Throw cs540::ArgsMismatchException" << std::endl;
}
return raw_string;
}
template <typename T, typename ...Args>
std::string Interpolate(std::string raw_string, T arg_head, Args... arg_tail) {
std::size_t found = raw_string.find_first_of("%");
while(found != 0 && raw_string[found-1] == '\\') {
found = raw_string.find_first_of("%", found + 1);
}
if(found == std::string::npos) {
std::cout << "Throw cs540::ArgsMismatchException." << std::endl;
}
// Checking the typeid of the arg_head, and converting it to a string, and concatenating the strings together.
else {
if(std::is_arithmetic<T>::value) {
raw_string = raw_string.substr(0, found) + std::to_string(arg_head) + raw_string.substr(found + 1, raw_string.size());
}
}
return Interpolate(raw_string, arg_tail...);
}
int main(void) {
int i = 24332;
float x = 432.321;
std::string str1("foo");
//Works
std::cout << Interpolate(R"(goo % goo % goo)", i, x) << std::endl;
// Does not work, even though I'm not actually doing anything with the string argument
std::cout << Interpolate(R"(goo %)", str1) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这是语义上的运行时检查.这意味着{}编译中的代码,即使表达式始终为false:
if(std::is_arithmetic<T>::value) {
raw_string = raw_string.substr(0, found) + std::to_string(arg_head) + raw_string.substr(found + 1, raw_string.size());
}
Run Code Online (Sandbox Code Playgroud)
解决这个问题,你可以这样做:
template<typename T>
void do_arithmetic( std::string& raw_string, T&& t, std::true_type /* is_arthmetic */ ) {
raw_string = raw_string.substr(0, found) + std::to_string(std::forward<T>(t)) + raw_string.substr(found + 1, raw_string.size());
}
template<typename T>
void do_arithmetic( std::string& raw_string, T&& t, std::false_type /* is_arthmetic */ ) {
// do nothing
}
Run Code Online (Sandbox Code Playgroud)
然后输入你的代码:
do_arithmetic( raw_string, arg_head, std::is_arithmetic<T>() );
Run Code Online (Sandbox Code Playgroud)
这是一个编译时分支.类型std::is_arithmetic是true_type或者false_type取决于是否T算术.这导致do_arithmetic调用不同的重载.
在C++ 1y中,您可以内联执行此操作.
template<typename F, typename...Args>
void do_if(std::true_type, F&& f, Args&&... args){
std::forward<F>(f)( std::forward<Args>(args)... );
}
template<typename...Args>
void do_if(std::false_type, Args&&...){
}
template<bool b,typename...Args>
void do_if_not(std::integral_constant<bool,b>, Args&& args){
do_if( std::integral_constant<bool,!b>{}, std::forward<Args>(args)... );
}
template<typename C, typename F_true, typename F_false, typename...Args>
void branch( C c, F_true&&f1, F_false&& f0, Args&&... args ){
do_if(c, std::forward<F_true>(f1), std::forward<Args>(args)... );
do_if_not(c, std::forward<F_false>(f0), std::forward<Args>(args)... );
}
Run Code Online (Sandbox Code Playgroud)
这是样板.然后我们可以在我们的功能中做:
do_if(std::is_arithmetic<T>{},
[&](auto&& arg_head){
raw_string = raw_string.substr(0, found) + std::to_string(arg_head) + raw_string.substr(found + 1, raw_string.size());
},
arg_head
);
Run Code Online (Sandbox Code Playgroud)
或者,如果你想要两个分支:
branch(std::is_arithmetic<T>{},
[&](auto&& x){
raw_string = std::to_string(x); // blah blah
}, [&](auto&&) {
// else case
},
arg_head
);
Run Code Online (Sandbox Code Playgroud)
并且第一种方法仅在x=arg_headif is_arithmetic为true 时才被实例化.
需要抛光,但有点整洁.
| 归档时间: |
|
| 查看次数: |
308 次 |
| 最近记录: |