递归可迭代模板函数 C++
recursive iterable template functions c++
我对如何将类型信息传递到递归链感到困惑。
以下代码的目标是做一些类似于python的",".join(["a","b","c"])
的事情,但递归,以便我可以加入数组的数组数组...字符串,其中分隔符的数量与结构深度一样多。
这是我有点注释掉的(试图让它编译)代码:
#include <iostream>
#include <typeinfo>
#include <vector>
template <typename RAI>
std::string string_join(RAI begin, RAI end, std::string delimiter) {
if (begin == end) { return ""; }
std::string joint = std::to_string(*begin);
begin++;
for (; begin != end; begin++) {
joint += delimiter + std::to_string(*begin);
}
return joint;
}
template <typename RAI, int depth>
struct string_join_recursive {
std::string operator()(RAI iterator, std::string *delimiter, int *dimensions) {
typedef typename std::iterator_traits<RAI>::value_type::iterator value_iterator_type;
std::cout << typeid(value_iterator_type).name() << " " << typeid(std::begin(*iterator)).name() << std::endl;
std::string joint = string_join_recursive<value_iterator_type, depth-1>(std::begin(*iterator), delimiter+1, dimensions+1);
iterator++;
for (int i=1; i<*dimensions; i++) {
//joint += *delimiter + string_join_recursive<value_iterator_type, depth-1>(std::begin(*iterator), delimiter+1, dimensions+1);
iterator++;
}
return "";//joint;
}
};
template <typename RAI>
struct string_join_recursive<RAI,1> {
std::string operator()(RAI iterator, std::string *delimiter, int *dimensions) {
return string_join(iterator, iterator + *dimensions, *delimiter);
}
};
int main() {
std::vector<std::vector<int>> a;
std::vector<int> b = {1,2,3};
std::vector<int> c = {1,2,4};
std::string delimiters[2] = {"n",","};
int dimensions[2] = {2, 3};
std::cout << string_join_recursive<std::vector<std::vector<int>>::iterator, 2>()(a.begin(), delimiters, dimensions) << std::endl;
}
我不是资深的 c++ 程序员,所以这可能有多个问题,但目前它甚至不会编译。 显然value_iterator_type
不是我认为的程序运行时的类型,但我不确定它到底是什么。 OTOH,当我注释掉第 5 行时,它会编译,上面的打印行说这两个东西是相同的类型。
这是我得到的错误:
error: no matching function for call to ‘string_join_recursive<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, 1>::string_join_recursive(std::vector<int>::iterator, std::__cxx11::string*, int*)’
std::string joint = string_join_recursive<value_iterator_type, depth-1>(std::begin(*iterator), delimiter+1, dimensions+1);
以更清洁的方式做这件事的方法的奖励积分。使用任意可迭代对象(数组等)使其工作的方法的更多奖励积分
以下是我如何处理它的草图:
#include <iostream>
#include <algorithm>
#include <type_traits>
#include <sstream>
#include <vector>
#include <tuple>
// this allows us to test if a element should be recursed into
template <typename iterable, typename tag = void>
struct is_iterable
{
static constexpr bool value = false;
};
template <typename iterable>
struct is_iterable <iterable, std::void_t <decltype (std::begin (std::declval <iterable> ()))>>
{
static constexpr bool value = true;
};
template <typename iterable>
constexpr bool is_iterable_v = is_iterable <iterable>::value;
// visit elements of a tuple
template <size_t Index, typename visitor, typename ...types>
void visit_tuple (std::tuple <types...> const & Tuple, visitor && Visitor)
{
Visitor (std::get <Index> (Tuple));
constexpr auto nextIndex = Index + 1;
if constexpr (nextIndex < sizeof... (types))
visit_tuple <nextIndex> (Tuple, Visitor);
}
// this function generically walks the elements of a container, with an overload for tuples and pairs
template <typename container, typename visitor>
std::enable_if_t <is_iterable_v <container>>
visit_elements (container const & Container, visitor && Visitor)
{
for (auto && Element: Container)
Visitor (Element);
}
template <typename visitor, typename ...element_types>
void visit_elements (std::tuple <element_types...> const & Tuple, visitor && Visitor)
{
if constexpr (sizeof... (element_types) > 0)
visit_tuple <0> (Tuple, Visitor);
}
template <typename visitor, typename first_type, typename second_type>
void visit_elements (std::pair <first_type, second_type> const & Pair, visitor && Visitor)
{
Visitor (Pair.first);
Visitor (Pair.second);
}
// type trait for testing if a value is "visitable"
struct dummy_visitor { template <typename type> void operator () (type &&); };
template <typename container, typename tag = void>
struct is_visitable
{
static constexpr bool value = false;
};
template <typename container>
struct is_visitable <container, std::void_t <decltype (visit_elements (std::declval <container> (), dummy_visitor()))>>
{
static constexpr bool value = true;
};
template <typename container>
constexpr bool is_visitable_v = is_visitable <container>::value;
// this function walks each item and either emits it or recurses into it
template <typename iterable>
bool join_impl (std::ostream & os, char delim, bool emitted_anything, iterable const & Iterable)
{
using std::begin;
using std::end;
visit_elements (Iterable, [&] (auto && Element) {
if constexpr (!is_visitable_v <decltype (Element)>)
{
if (emitted_anything)
os << delim;
os << Element;
emitted_anything = true;
}
else
{
emitted_anything = join_impl (os, delim, emitted_anything, Element);
}
});
return emitted_anything;
}
// these are wrappers to adapt join_impl for different use cases
template <typename container>
struct joiner
{
char delim;
container const & Container;
operator std::string () const { return to_string <char> (); }
template <typename char_t>
std::basic_string <char_t> to_string () const;
};
template <typename container>
std::ostream & operator << (std::ostream & os, joiner <container> j)
{
bool emitted_anything = false;
join_impl (os, j.delim, emitted_anything, j.Container);
return os;
}
template <typename container>
template <typename char_t>
std::basic_string <char_t> joiner <container>::to_string () const
{
std::ostringstream os;
os << *this;
return os;
}
template <typename container>
std::enable_if_t <is_visitable_v <container>, joiner <container>>
join (char delim, container const & Container)
{
return joiner <container> { delim, Container };
}
// test the streaming use case
int main ()
{
std::vector <std::vector <std::tuple <int, float>>> x {
{ { 1, 1.0f }, { 2, 2.0f }},
{ { 3, 3.0f }, { 4, 4.0f }},
};
std::cout << join (',', x) << std::endl;
}
这应该只适用于支持标准迭代协议的任何递归。它还支持元组和对。In 可以通过定义访问每个公开字段的重载来扩展到用户定义结构visit_elements
。is_iterable
型特征需要在其预期的界面中更精确地工作。
我设法清理了错误。 我只是误称函子。 我这样做的初衷是让它也适用于数组,但它没有。 无论如何,这基本上是一个任意维度的 csv 编写器。
#include <iostream>
#include <typeinfo>
#include <vector>
template <typename RAI>
std::string string_join(RAI begin, RAI end, std::string delimiter) {
if (begin == end) { return ""; }
std::string joint = std::to_string(*begin);
begin++;
for (; begin != end; begin++) {
joint += delimiter + std::to_string(*begin);
}
return joint;
}
template <typename RAI, int depth>
struct string_join_recursive {
std::string operator()(RAI iterator, std::string *delimiters, int *dimensions) {
typedef typename std::iterator_traits<RAI>::value_type::iterator value_iterator_type;
std::string joint = string_join_recursive<value_iterator_type, depth-1>()(std::begin(*iterator), delimiters+1, dimensions+1);
iterator++;
for (int i=1; i<*dimensions; i++) {
joint += *delimiters + string_join_recursive<value_iterator_type, depth-1>()(std::begin(*iterator), delimiters+1, dimensions+1);
iterator++;
}
return joint;
}
};
template <typename RAI>
struct string_join_recursive<RAI,1> {
std::string operator()(RAI iterator, std::string *delimiters, int *dimensions) {
return string_join(iterator, iterator + *dimensions, *delimiters);
}
};
int main() {
std::vector<int> a = {1,2,3};
std::vector<int> b = {4,5,6};
std::vector<int> c = {7,8,9};
std::vector<int> d = {10,11,12};
std::vector<std::vector<int>> e = {a,b};
std::vector<std::vector<int>> f = {c,d};
std::vector<std::vector<std::vector<int>>> g = {e,f};
std::string delimiters[3] = {"n",";",","};
int dimensions[3] = {2, 2, 3};
std::cout << string_join_recursive<std::vector<std::vector<std::vector<int>>>::iterator, 3>()(g.begin(), delimiters, dimensions) << std::endl;
}
相关文章:
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗