Insert/get 元组 into/from 元组向量
Insert/get tuple into/from vector of tuples
我正在尝试 insert/get 一个元组 into/from 一个元组向量,并提出了以下代码片段。它工作正常,但我对它并不完全满意。
谁能想到一个更优雅的解决方案?是否可以将 'for_each_in_tuple_and_arg' 函数泛化为 'for_each_in_tuples' 函数?
PS:我受困于 C++14 编译器...
#include <tuple>
#include <vector>
#include <utility>
template <std::size_t I = 0, class Fn, class Tuple>
constexpr typename std::enable_if
<I == std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&&, Tuple&) {}
template <std::size_t I = 0, class Fn, class Tuple>
constexpr typename std::enable_if
<I != std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&& fn, Tuple& tup)
{
fn(std::get<I>(tup));
for_each_in_tuple<I + 1>(fn, tup);
}
template <std::size_t I = 0, class Fn, class Tuple, class Arg>
constexpr typename std::enable_if
<I == std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple_and_arg(Fn&&, Tuple&, const Arg&) {}
template <std::size_t I = 0, class Fn, class Tuple, class Arg>
constexpr typename std::enable_if
<I != std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple_and_arg(Fn&& fn, Tuple& tup, const Arg& arg)
{
fn(std::get<I>(tup), std::get<I>(arg));
for_each_in_tuple_and_arg<I + 1>(fn, tup, arg);
}
class tuple_of_vectors
{
public:
using tov_type = std::tuple<
std::vector<int>, std::vector<int>, std::vector<int>>;
using value_type = std::tuple<int, int, int>;
void reserve(std::size_t n)
{
auto fn = [n](auto& vec){ vec.reserve(n); };
for_each_in_tuple(fn, tov_);
}
value_type at(std::size_t n) const noexcept
{
value_type res{};
auto fn = [n](auto& val, const auto& vec)
{ val = vec.at(n); };
for_each_in_tuple_and_arg(fn, res, tov_);
return res;
}
void insert(const value_type& tup)
{
std::size_t n = 0;
auto fn = [n](auto& vec, const auto& val)
{ vec.insert(vec.cbegin() + n, val); };
for_each_in_tuple_and_arg(fn, tov_, tup);
}
tov_type tov_;
};
只需添加可变模板参数:
template <std::size_t I = 0, class Fn, class Tuple, class ... Tuples>
constexpr typename std::enable_if
<I == std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&&, Tuple&, Tuples&& ...) {}
template <std::size_t I = 0, class Fn, class Tuple, class ... Tuples>
constexpr typename std::enable_if
<I != std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&& fn, Tuple& tup, Tuples&&... tuples)
{
fn(std::get<I>(tup), std::get<I>(std::forward<Tuples>(tuples))...);
for_each_in_tuple<I + 1>(fn, tup, std::forward<Tuples>(tuples)...);
}
class tuple_of_vectors
{
public:
using tov_type = std::tuple<
std::vector<int>, std::vector<int>, std::vector<int>>;
using value_type = std::tuple<int, int, int>;
void reserve(std::size_t n)
{
auto fn = [n](auto& vec) { vec.reserve(n); };
for_each_in_tuple(fn, tov_);
}
value_type at(std::size_t n) const noexcept
{
value_type res{};
auto fn = [n](auto& val, const auto& vec)
{ val = vec.at(n); };
for_each_in_tuple(fn, res, tov_);
return res;
}
void insert(const value_type& tup)
{
std::size_t n = 0;
auto fn = [n](auto& vec, const auto& val)
{ vec.insert(vec.cbegin() + n, val); };
for_each_in_tuple(fn, tov_, tup);
}
tov_type tov_;
};
因为在当前的 C++ 中很容易写出这样的东西,可以是这样的:
template <typename TUPPLE_T, typename FUNC, typename ... ARGS >
void for_each_in_tuple( TUPPLE_T& tu, FUNC fn, ARGS... args )
{
std::apply( [&args..., fn]( auto& ... n) { (fn(args..., n),...); }, tu);
}
int main()
{
std::tuple< int, int> tu{1,2};
auto l_incr = [](int& i){i++;};
auto l_add = []( int val, int& i){i+=val; };
for_each_in_tuple( tu, l_incr );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
for_each_in_tuple( tu, l_add, 5 );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
}
但你固定在 C++14。好的,让我们根据需要从 STL 中复制和最小化内容,以使其与“手工制作”的应用功能一起使用,例如:
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
return f(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
return detail::apply_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
// Workaround for missing fold expression in C++14. Simply use
// list initializer to get function called. It guarantees also
// execution order...
struct EatEverything
{
template < typename ... T>
EatEverything(T...){}
};
template <typename TUPPLE_T, typename FUNC, typename ... ARGS >
void for_each_in_tuple( TUPPLE_T& tu, FUNC fn, ARGS... args )
{
apply( [&args..., fn]( auto& ... n) { EatEverything{ (fn(args..., n),0)... };}, tu);
}
int main()
{
std::tuple< int, int> tu{1,2};
auto l_incr = [](int& i){i++;};
auto l_add = []( int val, int& i){i+=val; };
for_each_in_tuple( tu, l_incr );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
for_each_in_tuple( tu, l_add, 5 );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
}
因为我们只写了一个 C++14 apply 函数,我们可以稍后删除那些东西,同时可以使用非过时的编译器,我们保持单行代码实现。
提示:我知道我们可以通过使用转发 refs 和 std::forward
等来更好地完成所有事情......这是一个例子,想展示我们如何使用 apply 而不是 handcrafted反向算法。
我正在尝试 insert/get 一个元组 into/from 一个元组向量,并提出了以下代码片段。它工作正常,但我对它并不完全满意。 谁能想到一个更优雅的解决方案?是否可以将 'for_each_in_tuple_and_arg' 函数泛化为 'for_each_in_tuples' 函数? PS:我受困于 C++14 编译器...
#include <tuple>
#include <vector>
#include <utility>
template <std::size_t I = 0, class Fn, class Tuple>
constexpr typename std::enable_if
<I == std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&&, Tuple&) {}
template <std::size_t I = 0, class Fn, class Tuple>
constexpr typename std::enable_if
<I != std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&& fn, Tuple& tup)
{
fn(std::get<I>(tup));
for_each_in_tuple<I + 1>(fn, tup);
}
template <std::size_t I = 0, class Fn, class Tuple, class Arg>
constexpr typename std::enable_if
<I == std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple_and_arg(Fn&&, Tuple&, const Arg&) {}
template <std::size_t I = 0, class Fn, class Tuple, class Arg>
constexpr typename std::enable_if
<I != std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple_and_arg(Fn&& fn, Tuple& tup, const Arg& arg)
{
fn(std::get<I>(tup), std::get<I>(arg));
for_each_in_tuple_and_arg<I + 1>(fn, tup, arg);
}
class tuple_of_vectors
{
public:
using tov_type = std::tuple<
std::vector<int>, std::vector<int>, std::vector<int>>;
using value_type = std::tuple<int, int, int>;
void reserve(std::size_t n)
{
auto fn = [n](auto& vec){ vec.reserve(n); };
for_each_in_tuple(fn, tov_);
}
value_type at(std::size_t n) const noexcept
{
value_type res{};
auto fn = [n](auto& val, const auto& vec)
{ val = vec.at(n); };
for_each_in_tuple_and_arg(fn, res, tov_);
return res;
}
void insert(const value_type& tup)
{
std::size_t n = 0;
auto fn = [n](auto& vec, const auto& val)
{ vec.insert(vec.cbegin() + n, val); };
for_each_in_tuple_and_arg(fn, tov_, tup);
}
tov_type tov_;
};
只需添加可变模板参数:
template <std::size_t I = 0, class Fn, class Tuple, class ... Tuples>
constexpr typename std::enable_if
<I == std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&&, Tuple&, Tuples&& ...) {}
template <std::size_t I = 0, class Fn, class Tuple, class ... Tuples>
constexpr typename std::enable_if
<I != std::tuple_size<Tuple>::value, void>::type
for_each_in_tuple(Fn&& fn, Tuple& tup, Tuples&&... tuples)
{
fn(std::get<I>(tup), std::get<I>(std::forward<Tuples>(tuples))...);
for_each_in_tuple<I + 1>(fn, tup, std::forward<Tuples>(tuples)...);
}
class tuple_of_vectors
{
public:
using tov_type = std::tuple<
std::vector<int>, std::vector<int>, std::vector<int>>;
using value_type = std::tuple<int, int, int>;
void reserve(std::size_t n)
{
auto fn = [n](auto& vec) { vec.reserve(n); };
for_each_in_tuple(fn, tov_);
}
value_type at(std::size_t n) const noexcept
{
value_type res{};
auto fn = [n](auto& val, const auto& vec)
{ val = vec.at(n); };
for_each_in_tuple(fn, res, tov_);
return res;
}
void insert(const value_type& tup)
{
std::size_t n = 0;
auto fn = [n](auto& vec, const auto& val)
{ vec.insert(vec.cbegin() + n, val); };
for_each_in_tuple(fn, tov_, tup);
}
tov_type tov_;
};
因为在当前的 C++ 中很容易写出这样的东西,可以是这样的:
template <typename TUPPLE_T, typename FUNC, typename ... ARGS >
void for_each_in_tuple( TUPPLE_T& tu, FUNC fn, ARGS... args )
{
std::apply( [&args..., fn]( auto& ... n) { (fn(args..., n),...); }, tu);
}
int main()
{
std::tuple< int, int> tu{1,2};
auto l_incr = [](int& i){i++;};
auto l_add = []( int val, int& i){i+=val; };
for_each_in_tuple( tu, l_incr );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
for_each_in_tuple( tu, l_add, 5 );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
}
但你固定在 C++14。好的,让我们根据需要从 STL 中复制和最小化内容,以使其与“手工制作”的应用功能一起使用,例如:
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>)
{
return f(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply(F&& f, Tuple&& t)
{
return detail::apply_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
// Workaround for missing fold expression in C++14. Simply use
// list initializer to get function called. It guarantees also
// execution order...
struct EatEverything
{
template < typename ... T>
EatEverything(T...){}
};
template <typename TUPPLE_T, typename FUNC, typename ... ARGS >
void for_each_in_tuple( TUPPLE_T& tu, FUNC fn, ARGS... args )
{
apply( [&args..., fn]( auto& ... n) { EatEverything{ (fn(args..., n),0)... };}, tu);
}
int main()
{
std::tuple< int, int> tu{1,2};
auto l_incr = [](int& i){i++;};
auto l_add = []( int val, int& i){i+=val; };
for_each_in_tuple( tu, l_incr );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
for_each_in_tuple( tu, l_add, 5 );
std::cout << std::get<0>(tu) << ":" << std::get<1>(tu) << std::endl;
}
因为我们只写了一个 C++14 apply 函数,我们可以稍后删除那些东西,同时可以使用非过时的编译器,我们保持单行代码实现。
提示:我知道我们可以通过使用转发 refs 和 std::forward
等来更好地完成所有事情......这是一个例子,想展示我们如何使用 apply 而不是 handcrafted反向算法。