相信既学过Python也学过c++的年轻开发者们对于Python的print与input都认为非常好用,print一次性打印字典,元组,或者列表的所有元素,input输入同理。一开始从C过度到C++的时候认为cou与cint的流对象重载<< >>方式挺好的,但是现在,我们显然不满足于这些。
1、 首先我们要知道,为什么一个函数可以接收无限的参数调用?
可变参数,得益与可变参数我们可以写出类似于c语言的printf,scnaf,Python的print。c语言作为c++的子集,我们可以使用它的可变参数方案,但是,可以但没必要。
c语言的可变参数是使用宏定义的,效率的确会高,但是使用并不方便。
c++自c++17以来的折叠表达式,让我们对可变参数模板使用变得轻松,我们今天选择更加新式的range,来自于C++20,当然也提供之前的c++17的折叠表达式。学过Python的,对于range相信不会陌生,我们先编写print的代码,如下
namespace show_ {
template
void print(const T(&n)[i], const std::string s=" ") {
std::copy(std::begin(n),std::end(n), std::ostream_iterator(std::cout, s.data()));
std::cout << std::endl;
}
template
void print(const std::array v, const std::string s = " ") {
std::copy(std::begin(v), std::end(v), std::ostream_iterator(std::cout, s.data()));
std::cout << std::endl;
}
void print(const char* s) {
std::cout << s << std::endl; //重载特殊情况,字符串常量输出
}
void print(char* s) {
std::cout << s << std::endl; //重载特殊情况,字符串常量输出
}
template
void print(const std::vectorn,const std::string s=" ") {
std::copy(std::begin(n), std::end(n), std::ostream_iterator(std::cout, s.data()));
std::endl(std::cout);
}
template
void print(T v) {
std::cout << v << std::endl;
}
template
void print(const std::list& L,std::string s=" ") {
for (auto it = L.begin(); it != L.end(); it++) { //list容器版本
std::cout << *it << s;
}
std::cout << std::endl;
}
template
void print(_Type1 _Value1, _Type2 _Value2, _Types... _Values)//c++17折叠表达式
requires (sizeof...(_Types) > 0 || (!std::is_same_v && !std::is_same_v))//requires是c++20的
{
std::cout << _Value1 << " " << _Value2 << " ";
((std::cout << _Values <<" "), ...);
}
namespace object { //这真是无奈之举,这个匹配,object命名空间内的除了遍历vector和array的数组外,标准数据类型直接打印也可行
template
std::ostream& operator<<(std::ostream& os, const std::vector& data)
{
for (auto& str : data)
{
os << str<<" ";
}
return os;
}
template
std::ostream& operator<<(std::ostream& os, const std::array& data)
{
for (auto& str : data)
{
os << str<<" ";
}
return os;
}
void print() {}
template
void print(T first, Types...args) {
std::cout << first << '\n';
print(args...);
return;
}
}
namespace range { //没办法重载多了就是匹配问题,我能这里使用c++20的range
void print_impl(std::ostream& out, std::ranges::range auto&& r)
{
for (auto&& elem : r)
{
out << elem << " ";
}
std::cout << std::endl;
}
void print_impl(std::ostream& out, auto&& elem)
{
out << elem << " ";
std::cout << std::endl;
}
void print(auto&&...args)
{
(print_impl(std::cout, args), ...);
}
}
namespace rangeClass { //也可以写成一个类,主要是为了防止让print_impl暴露在外部接口,因为print同名的缘故所以我们无法写在一起
class print {
public:
void operator()(auto&&...args)
{
(print_impl(std::cout, args), ...);
}
private:
void print_impl(std::ostream& out, std::ranges::range auto&& r)
{
for (auto&& elem : r)
{
out << elem << " ";
}
std::cout << std::endl;
}
void print_impl(std::ostream& out, auto&& elem)
{
out << elem << " ";
std::cout << std::endl;
}
};
}
}
推荐放入头文件内,且我们需要C++的vector,array,ostream,range等标准库
使用的时候可以#include<......> using namespace show_;
更多的方式还请自己探索,这不是最优解,等我有兴趣的时候或许会重构此代码
namespace input_ {
template
void input(T(&v)[size],std::string str="")//裸数组版本重载
{
if (str[0])std::cout << str;
for (auto& i : v)std::cin >> i;
}
template
void input(char(&v)[size], std::string str = "")//是上一个模板的偏特化,这倒是比之前的print高明
{
if (str[0])std::cout << str;
std::cin.getline(v, size);
}
template //string对象的输入
void input(T &v, std::string str = "")
{
if (str[0])std::cout << str;
std::cin >> v;
}
template //vector版本
void input(std::vector&v, size_t size,std::string str="")
{
if (str[0])std::cout << str;
v.resize(size);
for (int i = 0; i < size; i++)std::cin >> v[i];
}
template
void input(std::array& v, std::string str = "")
{
if (str[0])std::cout << str;
for (int i = 0; i < size; i++)std::cin >> v[i];
}
/*-----------------------------------------------------------------*/
void print_impl(std::istream& out, std::ranges::range auto&& r) //不得不承认,得益于C++20,一切皆可
{
for (auto&& elem : r)
{
out >> elem;
}
}
void print_impl(std::istream& out, auto&& elem)
{
out >> elem;
}
void input(auto&&...args)
{
(print_impl(std::cin, args), ...);
}
}
input,这个倒是要清晰一点,可以联合在一起使用
#include<....>
using namespace show_;
using namespace input;
那么就可以开始愉快的使用print与input了
肯定有小白问了,怎么放到标准库里面用尖括号导入
以vs示范,随便找一个标准库的头文件右击,转到文档
看这张图最右边,vector,右击它
打开所在文件夹,然后就可以直接把自己写的头文件复制进去就行了
环境:msvc(vs2022) x86 debug C++20 未开启优化
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)