【发布时间】:2019-04-18 17:16:41
【问题描述】:
让我们考虑一个用于打印派生类的 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>>;
};
如果我使用 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 课程?
【问题讨论】:
-
你能发布一个完整的例子吗?我最初的预感是
auto self() const -> T是罪魁祸首,因为您实际上返回了整个对象。即使主体转换为引用返回也会复制对象。我懒得编译一个活生生的例子来测试。 -
我很少使用尾随返回类型,但
self是否返回this的副本? -
是的,你是对的,我做了一个副本,我没有注意,但是在 int 上,这无论如何也解决不了任何问题。不过我更正了它并添加了一个主要功能。
-
尤达记法为什么喜欢你?
auto print() const -> void; -
我喜欢生锈...嗯,这几乎是唯一的原因:P