首先,代码供参考(不要担心<<
重载,原来一切都在命名空间中):
#include <bits/stdc++.h>
// structures for checking if given variable is container
template <typename Container>
struct is_container : std::false_type { };
template<typename... Ts>
struct is_container<std::vector<Ts...>> : std::true_type { };
template<typename... Ts>
std::ostream& operator << (std::ostream& os, std::vector<Ts...>) {return os;}
template<typename... Ts>
struct is_container<std::deque<Ts...>> : std::true_type { };
template<typename... Ts>
std::ostream& operator << (std::ostream& os, std::deque<Ts...>) {return os;}
template<typename... Ts>
struct is_container<std::list<Ts...>> : std::true_type { };
template<typename... Ts>
std::ostream& operator << (std::ostream& os, std::list<Ts...>) {return os;}
//... the rest of containers in like manner, not necessary for this example
//function that prints given container (begin() and end() are required)
//this function is instantiated also for non-printable containers, but then is never called
//that's why I had to overload << operator, so it may instantiate for them
template<template<typename ...>
class C ,
typename T>
void print(const C<T>& cont,
const char& separator = ',',
const std::deque<std::pair<char,char>>& closures = {{'(', ')'}});
//function that prints to console given nested container. Container has to be at least one-level nested
//so it will accept f.e. vector of vectors of ints, but will reject vector of int
template<int Depth,
template<typename ...>
class C ,
typename T,
typename = typename std::enable_if<is_container<T>::value>::type>
void print_nested(const C<T>& cont,
const char& separator = ',',
const std::deque<std::pair<char,char>>& closures = {{'{','}'},{'[',']'},{'(',')'}},
unsigned depth = 0 );
//placebo template function to handle calls, where containers aren't nested (kind of fake instantiation)
template<int Depth, typename T>
void print_nested(const T&,
const char& ,
const std::deque<std::pair<char,char>>&,
unsigned);
//definition of above
template<int Depth, typename T>
void print_nested(const T&,
const char& ,
const std::deque<std::pair<char,char>>&,
unsigned)
{}
//definition of function printing non-nested container
template<template<typename ...> class C , typename T>
void print(const C<T>& cont,
const char& separator,
const std::deque<std::pair<char,char>>& closures)
{
std::cout << closures[0].first;
for(auto it=cont.begin(); it!=cont.end(); )
{
std::cout << *it;
if(++it != cont.end())
std::cout << separator << " ";
}
std::cout << closures[0].second;
}
//definition of main function, which handles printing nested containers
template<int Depth,
template<typename ...> class C ,
typename T,
typename = typename std::enable_if<is_container<T>::value>::type>
void print_nested(const C<T>& cont,
const char& separator,
const std::deque<std::pair<char,char>>& closures,
unsigned depth)
{
if(depth < Depth)
++depth;
std::cout << closures[0].first;
for(auto it=cont.begin(); it!=cont.end(); )
{
if(it!=cont.begin())
std::cout << std::string(depth, ' ');
if(is_container<typename T::value_type>::value)
print_nested<Depth>(*it,
separator,
(closures.size() > 1)?
std::deque<std::pair<char,char>>(closures.begin()+1, closures.end()) : closures,
depth
);
else
print(*it,
separator,
(closures.size() > 1)?
std::deque<std::pair<char,char>>(closures.begin()+1, closures.end()) : closures
);
if(++it != cont.end())
std::cout << separator << std::endl;
}
std::cout << closures[0].second;
}
void gimme_some_space(std::string anger = "")
{
std::for_each(anger.begin(), anger.end(), [](char c) {if(c=='!') std::cout << std::endl;});
}
int main()
{
//cases and calls:
std::vector<std::deque<std::list<int>>> nested {{{1,2,3},{3,4,5},{7,8,9}},{{9,8,7},{6,5,4},{3,2,1}}};
std::vector<int> not_nested {1,2,3,4,5};
print_nested<2>(nested); // target functionality
gimme_some_space("!!");
print_nested<0>(nested); // i'd like to omit <0> (set it as default non-type template parameter)
//print_nested<0>(not_nested); //excluded from overload set, non_nested is not nested
gimme_some_space("!!!");
print(not_nested); //call for printing non-nested container
gimme_some_space("!!!!");
}
这是工作吗?输出结果如下:
{[(1, 2, 3),
(3, 4, 5),
(7, 8, 9)],
[(9, 8, 7),
(6, 5, 4),
(3, 2, 1)]}
{[(1, 2, 3),
(3, 4, 5),
(7, 8, 9)],
[(9, 8, 7),
(6, 5, 4),
(3, 2, 1)]}
(1, 2, 3, 4, 5)
我的问题是:参数Depth决定缩进。它总是应该等于嵌套级别,对于非嵌套容器,它应该是0.但我甚至不希望它以某种方式检索有关嵌套给定容器的信息 - 相反 - 我想设置深度默认值为零。所以在模板参数中应该是:
int Depth = 0
但这使问题复杂化。如果它具有默认值,则不能将其置于参数列表的开头,因为容器C和该容器T的元素(当然类型)不是默认值。无论如何,让我们这样做:
template<template<typename ...> class C ,
typename T,
int Depth = 0,
typename = typename std::enable_if<is_container<T>::value>::type>
几乎完美。是吗? 这现在可以使用Depth set default to 0:
print_nested(nested);
但是如果我现在想要自己指定缩进怎么办?恐怖:
print_nested<std::vector<std::deque<std::list<int>>>, std::deque<std::list<int>>, 2>(nested);
你知道任何令人兴奋的方法来克服这个问题吗?
答案 0 :(得分:2)
您可以使用额外的参数。
std::integral_constant<std::size_t, Depth > maxDepth
怎么样,所以
template <std::size_t N> using Depth_t = std::integral_constant<std::size_t, N>;
template<template<typename ...> class C ,
typename T,
std::size_t Depth = 0,
typename = typename std::enable_if<is_container<T>::value>::type>
void print_nested(const C<T>& cont,
Depth_t<Depth> = {},
const char& separator = ',',
const std::deque<std::pair<char,char>>& closures = {{'{','}'},{'[',']'},
unsigned depth = 0
);
并称之为
print_nested(nested, Depth_t<2>{});