没有参考书,任何人都可以CRTP
用代码示例提供一个很好的解释吗?
我以为我很了解Java泛型,但后来我在java.lang.Enum中遇到了以下内容:
class Enum<E extends Enum<E>>
Run Code Online (Sandbox Code Playgroud)
有人可以解释如何解释这个类型参数?用于提供可以使用类似类型参数的其他示例的加分点.
我阅读了维基百科关于C++中用于执行静态(读取:编译时)多态的奇怪重复模板模式的文章.我想概括它,以便我可以根据派生类型更改函数的返回类型.(这似乎应该是可能的,因为基类型知道模板参数中的派生类型).不幸的是,以下代码将无法使用MSVC 2010进行编译(我现在没有轻松访问gcc所以我还没有尝试过).谁知道为什么?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
Run Code Online (Sandbox Code Playgroud)
顺便说一下,我有一个使用额外模板参数的解决方法,但我不喜欢它 - 当在继承链上传递许多类型时会变得非常冗长.
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public …
Run Code Online (Sandbox Code Playgroud) 我正在尝试在项目中使用子类的typedef,我在下面的示例中已经分离了我的问题.
有谁知道我哪里出错了?
template<typename Subclass>
class A {
public:
//Why doesn't it like this?
void action(typename Subclass::mytype var) {
(static_cast<Subclass*>(this))->do_action(var);
}
};
class B : public A<B> {
public:
typedef int mytype;
B() {}
void do_action(mytype var) {
// Do stuff
}
};
int main(int argc, char** argv) {
B myInstance;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我得到的输出:
sean@SEAN-PC:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp
test.cpp: In instantiation of ‘A<B>’:
test.cpp:10: instantiated from here
test.cpp:5: error: invalid use of incomplete type ‘class B’
test.cpp:10: error: forward …
Run Code Online (Sandbox Code Playgroud) 考虑以下:
template<typename Der>
struct Base {
// NOTE: if I replace the decltype(...) below with auto, code compiles
decltype(&Der::operator()) getCallOperator() const {
return &Der::operator();
}
};
struct Foo : Base<Foo> {
double operator()(int, int) const {
return 0.0;
}
};
int main() {
Foo f;
auto callOp = f.getCallOperator();
}
Run Code Online (Sandbox Code Playgroud)
我想在CRTP基类中创建一个成员函数,其返回类型取决于operator()
派生类中的签名.但decltype(&Der::operator())
无法编译; 将operator()
在成员函数Foo
是不可见的.我假设这是因为基类模板在Foo
完全定义之前被实例化.
令人惊讶的是,如果我auto
为返回类型放置它编译.我假设这auto
会使编译器从函数体中推导出返回类型并失败 - 因为正文使用了未完全定义的Foo
类型.
MSVC 2015.3和Clang 3.8的行为相同
为什么代码开始使用auto
?难道auto
类型推演莫名其妙"延迟"的实例?或者使用与手写返回类型表达式不同的上下文?
在我刚刚进行的测试之前,我相信只有构造函数不会在C++中继承.但显然,任务operator=
不是......
operator+=
,operator-=
...?事实上,我在做一些CRTP时遇到了这个问题:
template<class Crtp> class Base
{
inline Crtp& operator=(const Base<Crtp>& rhs) {/*SOMETHING*/; return static_cast<Crtp&>(*this);}
};
class Derived1 : public Base<Derived1>
{
};
class Derived2 : public Base<Derived2>
{
};
Run Code Online (Sandbox Code Playgroud)
是否有任何解决方案可以使其工作?
编辑:好的,我已经解决了这个问题.为什么以下不起作用?如何解决问题?
#include <iostream>
#include <type_traits>
// Base class
template<template<typename, unsigned int> class CRTP, typename T, unsigned int N> class Base
{
// Cast to base
public:
inline Base<CRTP, T, N>& operator()()
{
return *this;
}
// Operator =
public: …
Run Code Online (Sandbox Code Playgroud) 在CRTP模式中,如果我们想要将派生类中的实现函数保持为受保护,则会遇到问题.我们必须将基类声明为派生类的朋友或使用类似的东西(我没有尝试过链接文章的方法).是否有其他(简单)方法允许将派生类中的实现函数保持为受保护?
编辑:这是一个简单的代码示例:
template<class D>
class C {
public:
void base_foo()
{
static_cast<D*>(this)->foo();
}
};
class D: public C<D> {
protected: //ERROR!
void foo() {
}
};
int main() {
D d;
d.base_foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码给出error: ‘void D::foo()’ is protected
了g ++ 4.5.1,但是如果protected
被替换为compiles public
.
我无法想出一个适当的问题标题来描述问题.希望下面的细节清楚地解释了我的问题.
请考虑以下代码
#include <iostream>
template <typename Derived>
class Base
{
public :
void call ()
{
static_cast<Derived *>(this)->call_impl();
}
};
class D1 : public Base<D1>
{
public :
void call_impl ()
{
data_ = 100;
std::cout << data_ << std::endl;
}
private :
int data_;
};
class D2 : public Base<D1> // This is wrong by intension
{
public :
void call_impl ()
{
std::cout << data_ << std::endl;
}
private :
int data_;
};
int main ()
{
D2 …
Run Code Online (Sandbox Code Playgroud)