簡體   English   中英

CRTP 應用於模板類

[英]CRTP applied on a template class

讓我們考慮一個用於打印派生類的 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 的專業化來專業化我的打印方法,它會編譯並工作:

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 課程進行完全專業化?

只要你小心,你就可以以一種迂回的方式做到這一點。

現場演示

您的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");
    }
};

您將為您的Wrapper類部分地專門化這個PrintImpl

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類的實例之前聲明您的特化,這就會起作用。


您還可以為您的Integer類完全特化PrintImpl<T>::operator() ,而無需編寫類特化:

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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM