STD::元组实现C++

  • 本文关键字:C++ 实现 元组 STD c++
  • 更新时间 :
  • 英文 :


参考下面的代码,我发现很难理解元模板编程中递归和平面STD::元组实现之间的主要区别。如果可能的话,我希望有人能够解释两者之间的核心区别,以及为什么应该优先选择其中一个?此外,如果可能的话,解释一下每一个是如何为像我这样刚刚入门元模板编程的初学者工作的。我希望下面的代码能够帮助那些想知道STD::tuple在元模板编程中的实现的人。

#include <tuple>
#include <iostream>
#include <utility>

namespace flop
{
namespace recursion
{ 
template <typename...>
class leaf{};
template <typename CArg,typename... CArgs>
class leaf<CArg, CArgs...> :
public leaf<CArgs...>
{
public:
template <typename Targ,typename... Targs>
leaf(Targ&& num, Targs&&... nums) : 
leaf<CArgs...>(std::forward<Targs>(nums)...), 
_value{std::forward<Targ>(num)}
{
}
CArg _value;
};
template <typename... Ts>
using tuple = leaf<Ts...>;
template <size_t N,typename CArg,typename... CArgs>
class simplify_pack
{
public:
using type = typename simplify_pack<N - 1, CArgs...>::type;
};
template <
typename CArg,
typename... CArgs
>
class simplify_pack<0, CArg, CArgs...>
{
public:
using type = leaf<CArg, CArgs...>;
};
template <
size_t N,
typename... Ts
>
using simplify_pack_t = typename simplify_pack<N, Ts...>::type;
template <
size_t N,
typename... Ts
>
auto&  get(tuple<Ts...>& t)
{
using base = simplify_pack_t<N, Ts...>;
return static_cast<base&>(t)._value;
}
}
///////////////////////////////////////////////////////////////////////////////
namespace flat
{
template <size_t N,typename T>
class leaf
{
public:
template <typename Targ>
explicit leaf(Targ&& num) :
_value{std::forward<Targ>(num)}
{
}
T _value;
};
template <typename Seq,typename... Ts>
class tuple_implem{};
template <size_t... Ns,typename... Ts>
class tuple_implem<std::index_sequence<Ns...>,Ts...> 
: public leaf<Ns, Ts>...
{
public:
template <typename... Targs>
tuple_implem(Targs&&... nums) :
leaf<Ns, Ts>{std::forward<Targs>(nums)}...
{
}
};
template <typename... Ts>
using tuple = tuple_implem<
std::make_index_sequence< sizeof...(Ts) >,  
Ts...                                       
>;
template <size_t N,typename CArg,typename... CArgs>
auto N_type_search_f()
{
if constexpr (N == 0)
{
return CArg{};
}
else
{
return N_type_search_f<N - 1, CArgs...>();
}
}
template <
size_t N,
typename... Ts
>
using N_type_search = decltype( N_type_search_f<N, Ts...>() );
template <
size_t N,
typename... Ts
>
N_type_search<N, Ts...>& get(tuple<Ts...>& t)
{
using base = leaf<N, N_type_search<N, Ts...> >;
return static_cast<base&>(t)._value;
}
}
}
///////////////////////////////////////////////////////////////////////////////
int main()
{
std::cout << "std::tuple" << std::endl;
{
namespace myn_s = std;
myn_s::tuple<int, int, double> t{10, 20, 30.0};
auto print_tuple = [&]()
{
std::cout
<< "tFirst:t" << myn_s::get<0>(t) << "n"
<< "tSecond:t" << myn_s::get<1>(t) << "n"
<< "tThird:t" << myn_s::get<2>(t) << std::endl;
};
print_tuple();
myn_s::get<0>(t) += 100;
myn_s::get<1>(t) += 200;
myn_s::get<2>(t) += 300;
print_tuple();
}
std::cout << "flop::recursion::tuple" << std::endl;
{
namespace myn_s = flop::recursion;
myn_s::tuple<int, int, double> t{10, 20, 30.0};
auto print_tuple = [&]()
{
std::cout
<< "tFirst:t" << myn_s::get<0>(t) << "n"
<< "tSecond:t" << myn_s::get<1>(t) << "n"
<< "tThird:t" << myn_s::get<2>(t) << std::endl;
};
print_tuple();
myn_s::get<0>(t) += 100;
myn_s::get<1>(t) += 200;
myn_s::get<2>(t) += 300;
print_tuple();
}
std::cout << "flop::flat::tuple" << std::endl;
{
namespace myn_s = flop::flat;
myn_s::tuple<int, int, double> t{10, 20, 30.0};
auto print_tuple = [&]()
{
std::cout
<< "tFirst:t" << myn_s::get<0>(t) << "n"
<< "tSecond:t" << myn_s::get<1>(t) << "n"
<< "tThird:t" << myn_s::get<2>(t) << std::endl;
};
print_tuple();
myn_s::get<0>(t) += 100;
myn_s::get<1>(t) += 200;
myn_s::get<2>(t) += 300;
print_tuple();
}
}

为什么一个应该优先于另一个?

递归实现符合C++11,因此当以后的标准不可用时,它应该是首选,因为它是唯一的选项。所示的平面实现依赖于使用if constexpr的C++17和使用std::index_sequence的C++14。

在我看来,平面实现更简单。此外,我怀疑它的编译速度会更快,尽管我建议进行测量以验证其正确性。因此,当有足够的标准水平时,我更喜欢扁平化的实施。

最新更新