迭代元组......再次
Iterating on a tuple... again
我做C++已经有一段时间了,但我对模板不熟悉。
最近,我试图写一个 class 来包裹 std::vector<std::tuple<Types...>>
。这个 class 必须有成员函数,我真的需要能够 迭代 元组。事实上,如果我能够打印元组的每个元素(按顺序),我就能做我需要的一切。
我找到了一个使用转换的解决方案,但我对它不是很有信心,因为它基于我不太喜欢的转换(另外,当我尝试使用 static_cast
,它不再编译)。
我的问题是,下面的代码是否正确、可移植,它是否是 hack,我是否应该找到另一种方法来执行此操作而不是使用此转换?另外,这个演员表可能是运行时演员表吧?没有这个,有没有办法做我想做的事?
std::ostream& operator<<(std::ostream& out, std::tuple<> const& tuple)
{
return out; // Nothing to do here
}
template<typename First, typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<First, Types...> const& tuple)
{
out << std::get<0>(tuple) << " ";
// The cast that I don't like
return out << (std::tuple<Types...>&) tuple;
}
int main()
{
auto tuple = std::make_tuple(1, 2.3, "Hello");
std::cout << tuple << std::endl;
return 0;
}
提前感谢您的回答。
使用 std::index_sequence_for
来获得乐趣和利润。
template <typename TupleLike, size_t ... Inds>
std::ostream& PrintHelper(std::ostream& out, TupleLike const& tuple, std::index_sequence<Inds...>)
{
int unused[] = {0, (void(out << std::get<Inds>(tuple) << " "), 0)...};
(void)unused;
return out;
}
template<typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple)
{
return PrintHelper(out, tuple, std::index_sequence_for<Types...>());
}
编辑:Live Demo. Thanks to @dyp. This uses an expansion trick from .
我找到了另一种方法来做我想做的事。我使用 this article 可以按降序打印元组的元素,我使用第二个索引 J == std::tuple_size<std::tuple<Types...>>::value - I
所以我可以在 I==0
.
时专门化模板
template<std::size_t I, std::size_t J, typename... Types>
struct printHelper
{
std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple)
{
out << std::get<J>(tuple) << " ";
// Recursive call without cast
return printHelper<I-1,J+1,Types...>{}(out, tuple);
};
};
// Specialization on the last element when I==0
template<std::size_t J, typename... Types>
struct printHelper<0,J,Types...>
{
std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple)
{
// Nothing to do here
return out;
}
};
template<typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple)
{
return printHelper<std::tuple_size<std::tuple<Types...>>::value, 0, Types...>{}(out, tuple);
}
我做C++已经有一段时间了,但我对模板不熟悉。
最近,我试图写一个 class 来包裹 std::vector<std::tuple<Types...>>
。这个 class 必须有成员函数,我真的需要能够 迭代 元组。事实上,如果我能够打印元组的每个元素(按顺序),我就能做我需要的一切。
我找到了一个使用转换的解决方案,但我对它不是很有信心,因为它基于我不太喜欢的转换(另外,当我尝试使用 static_cast
,它不再编译)。
我的问题是,下面的代码是否正确、可移植,它是否是 hack,我是否应该找到另一种方法来执行此操作而不是使用此转换?另外,这个演员表可能是运行时演员表吧?没有这个,有没有办法做我想做的事?
std::ostream& operator<<(std::ostream& out, std::tuple<> const& tuple)
{
return out; // Nothing to do here
}
template<typename First, typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<First, Types...> const& tuple)
{
out << std::get<0>(tuple) << " ";
// The cast that I don't like
return out << (std::tuple<Types...>&) tuple;
}
int main()
{
auto tuple = std::make_tuple(1, 2.3, "Hello");
std::cout << tuple << std::endl;
return 0;
}
提前感谢您的回答。
使用 std::index_sequence_for
来获得乐趣和利润。
template <typename TupleLike, size_t ... Inds>
std::ostream& PrintHelper(std::ostream& out, TupleLike const& tuple, std::index_sequence<Inds...>)
{
int unused[] = {0, (void(out << std::get<Inds>(tuple) << " "), 0)...};
(void)unused;
return out;
}
template<typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple)
{
return PrintHelper(out, tuple, std::index_sequence_for<Types...>());
}
编辑:Live Demo. Thanks to @dyp. This uses an expansion trick from
我找到了另一种方法来做我想做的事。我使用 this article 可以按降序打印元组的元素,我使用第二个索引 J == std::tuple_size<std::tuple<Types...>>::value - I
所以我可以在 I==0
.
template<std::size_t I, std::size_t J, typename... Types>
struct printHelper
{
std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple)
{
out << std::get<J>(tuple) << " ";
// Recursive call without cast
return printHelper<I-1,J+1,Types...>{}(out, tuple);
};
};
// Specialization on the last element when I==0
template<std::size_t J, typename... Types>
struct printHelper<0,J,Types...>
{
std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple)
{
// Nothing to do here
return out;
}
};
template<typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple)
{
return printHelper<std::tuple_size<std::tuple<Types...>>::value, 0, Types...>{}(out, tuple);
}