让我们考虑一个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;
};

因为我想像基于派生类那样专门打印,所以我们可以通过重写来做到这一点,所以我还没有实现该方法。

我们可以包装一个整数,例如:
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>>;
};

如果我用包装器的特化方法来使我的打印方法特化,则它可以编译并起作用:
template <>
auto Print<Wrapper<int>>::print() const -> void
{
  cout << self().m_value << endl;
}

但是,如果我想说“对于Wrapper的所有专业 Realm ,都必须这样做”,那是行不通的:
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/

10-11 18:00