gpt4 book ai didi

c++ - 可变递归模板 mem 有趣的特化

转载 作者:行者123 更新时间:2023-11-30 01:19:33 28 4
gpt4 key购买 nike

这是我想写的代码:

template <typename T1, typename ... tail>
class record : public record<tail...>
{
using baseT = record<tail...>;

T1 elem;

public:
record(T1 first, tail... rest)
: elem(first), baseT(rest...)
{}

template <int index>
inline constexpr T1& get()
{
// line 83:
return baseT::get<index-1>();
}
// line 85:
template <>
inline constexpr T1& get<0>()
{
return elem;
}
};

我得到的编译器输出:(GCC 4.8.2 with -std=c++11)

record.hpp:85:15: error: explicit specialization in non-namespace scope 'class base::record<T1, tail>'
template <>
^
record.hpp:86:33: error: template-id 'get<0>' in declaration of primary template
inline constexpr T1& get<0>()
^
record.hpp: In member function 'constexpr T1& base::record<T1, tail>::get() const':
record.hpp:83:32: error: expected primary-expression before ')' token
return baseT::get<index-1>();
^

好的,我的意思很明确:类似于 std::tuple . get()旨在提供元素访问。

请帮助我让这个骨架正常工作;我所追求的是正确实现这种结构所需的理解;不过有 2 个具体问题:

  1. 特化的正确方法是什么get<0>()
  2. 什么会 typename... tail是,当编译器到达层次结构的根部时?

最佳答案

如果你想显式特化一个函数(成员函数,成员函数模板,..),那么你必须在命名空间范围内这样做:

template <typename T1, typename ... tail>
class record : public record<tail...>
{
using baseT = record<tail...>;

T1 elem;

public:
record(T1 first, tail... rest) // you should use perfect forwarding here
: elem(first), baseT(rest...)
{}

template <int index>
inline constexpr T1& get() // the `inline` is redundant here
{
// line 83:
return baseT::get<index-1>();
}
};

template<typename T1, typename ... tail>
template<>
inline constexpr T1& record<T1, tail...>::template get<0>()
{ return elem; }

但这是不允许的:您不能显式特化一个未显式特化的类模板的成员。在这里,record<T1, tail...>没有明确专门化;因此你可能没有明确地特化 get .

还有两个问题:

  1. get 的返回类型必须依赖于索引。
  2. 您的记录将递归地从自身派生。每次推导都会从 tail 中删除一个元素, 所以 tail最终是空的。然后,record<tail...>将失败,因为第一个模板参数 T1 tail 时无法设置是空的。因此,你需要专攻record

让它工作的一种方法是使用重载:

#include <type_traits>
#include <utility>

template<int N>
using int_const = std::integral_constant<int, N>;

template <typename T1, typename ... tail>
class record : public record<tail...>
{
using baseT = record<tail...>;

T1 elem;

protected:
using baseT::get_impl; // "unhide" the base class overloads

constexpr T1 const& get_impl(int_const<sizeof...(tail)>) const
{
return elem;
}

public:
template<typename T1_, typename ... tail_>
record(T1_&& first, tail_&&... rest)
: baseT(std::forward<tail_>(rest)...), elem(std::forward<T1_>(first))
{}

template <int index>
constexpr auto get() const
-> decltype( this->get_impl( int_const<sizeof...(tail) - index>{} ) )
{
static_assert(1+sizeof...(tail) > index, "out of bounds");
return this->get_impl( int_const<sizeof...(tail) - index>{} );
}
};

template <typename T1>
class record<T1>
{
T1 elem;

protected:
constexpr T1 const& get_impl(int_const<0>) const
{
return elem;
}

public:
template<typename T1_>
record(T1_&& first)
: elem(first)
{}

template <int index>
constexpr auto get() const
-> decltype( get_impl( int_const<index>{} ) )
{
static_assert(0 == index, "out of bounds");
return this->get_impl( int_const<index>{} );
}
};


#include <iostream>

int main()
{
record<int, double, char, bool> r{42, 1.2, 'c', false};
std::cout << r.get<1>() << '\n';
std::cout << r.get<0>() << '\n';
}

这是一个使用不同继承技术的例子:

#include <type_traits>
#include <utility>

template<int N>
using int_const = std::integral_constant<int, N>;

template<int N, class... Ts>
struct record_impl
{
struct out_of_bounds {};

template<int I>
constexpr out_of_bounds get(int_const<I>) const
{
static_assert(I < N, "out of bounds");
return {};
}
};

template<int N, class T, class... Ts>
struct record_impl<N, T, Ts...> : record_impl<N+1, Ts...>
{
using base = record_impl<N+1, Ts...>;

T mem;

template<class Arg, class... Args>
record_impl(Arg&& arg, Args&&... args)
: base(std::forward<Args>(args)...), mem(std::forward<Arg>(arg))
{}

using base::get;
constexpr T const& get(int_const<N>) const
{ return mem; }
};

template<class... Ts>
using record = record_impl<0, Ts...>;


#include <iostream>

int main()
{
record<int, double, char, bool> r{42, 1.2, 'c', false};
std::cout << r.get(int_const<0>{}) << '\n';
std::cout << r.get(int_const<3>{}) << '\n';
}

record_impl的用法允许摆脱额外的 get_impl .它还提供了放置 static_assert 的好机会在主模板的 get 中成员函数。

关于c++ - 可变递归模板 mem 有趣的特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20728949/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com