gpt4 book ai didi

c++ - 应用于模板类的 CRTP

转载 作者:行者123 更新时间:2023-11-30 04:54:59 27 4
gpt4 key购买 nike

让我们考虑一个用于打印派生类的 CRTP 模板类 Print:

template <typename T>
struct Print {
auto print() const -> void;
auto self() const -> T const & {
return static_cast<T const &>(*this);
}

private:
Print() {}
~Print() {}

friend T;
};

因为我想根据派生类来专门化打印,就像我们可以通过覆盖来做到这一点一样,所以我还没有实现该方法。

我们可以包装一个 Integer,例如:

class Integer :
public Print<Integer>
{
public:
Integer(int i) : m_i(i) {}

private:
int m_i;

friend Print<Integer>;
};

template <>
auto Print<Integer>::print() const -> void {
std::cout << self().m_i << std::endl;
}

目前为止一切正常,现在假设我想打印一个通用版本的包装器:

template <typename T>
class Wrapper :
public Print<Wrapper<T>>
{
public:
Wrapper(T value) : m_value(std::move(value)) {}

private:
T m_value;

friend Print<Wrapper<T>>;
};

如果我使用 Wrapper 的特化来特化我的 print 方法,它会编译并工作:

template <>
auto Print<Wrapper<int>>::print() const -> void
{
cout << self().m_value << endl;
}

但是如果我想说“对于 Wrapper 的所有特化,都这样做”,那是行不通的:

template <typename T>
auto Print<Wrapper<T>>::print() const -> void
{
cout << self().m_value << endl;
}

如果我在以下主函数上运行它:

auto main(int, char**) -> int {
auto i = Integer{5};
i.print();

auto wrapper = Wrapper<int>{5};
wrapper.print();

return 0;
}

编译器打印:

50:42: error: invalid use of incomplete type 'struct Print<Wrapper<T> >'
6:8: error: declaration of 'struct Print<Wrapper<T> >'

为什么?我怎样才能做到这一点 ?是否有可能或者我必须对我的 CRTP 类进行完全特化?

最佳答案

只要小心,您可以稍微迂回地执行此操作。

Live Demo

你的 Print类将依赖另一个类 PrintImpl进行打印。

#include <type_traits>

template<class...>
struct always_false : std::false_type{};

template<class T>
struct PrintImpl
{
void operator()(const T&) const
{
static_assert(always_false<T>::value, "PrintImpl hasn't been specialized for T");
}
};

您将部分特化这个 PrintImpl为你的 Wrapper类:

template<class T>
struct PrintImpl<Wrapper<T>>
{
void operator()(const Wrapper<T>& _val) const
{
std::cout << _val.m_value;
}
};

并确保Wrapper声明这个 PrintImpl成为friend :

friend struct PrintImpl<Wrapper<T>>;

Print类创建 PrintImpl 的实例并调用 operator() :

void print() const
{
PrintImpl<T>{}(self());
}

只要在实际实例化 Print 的实例之前声明您的特化,这就有效类。


你也可以完全专攻PrintImpl<T>::operator()为你的 Integer无需编写类特化的类:

class Integer :
public Print<Integer>
{
public:
Integer(int i) : m_i(i) {}

private:
int m_i;

friend PrintImpl<Integer>;
};

template <>
void PrintImpl<Integer>::operator()(const Integer& wrapper) const {
std::cout << wrapper.m_i << std::endl;
}

关于c++ - 应用于模板类的 CRTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53322234/

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