我想部分专门化一个现有的模板,我无法改变(std::tr1::hash)基类和所有派生类.原因是我使用奇怪的重复模板模式进行多态,并且哈希函数在CRTP基类中实现.如果我只想部分专门用于CRTP基类,那么它很简单,我可以写:
namespace std { namespace tr1 {
template <typename Derived>
struct hash<CRTPBase<Derived> >
{
size_t operator()(const CRTPBase<Derived> & base) const
{
return base.hash();
}
};
} }
Run Code Online (Sandbox Code Playgroud)
但是这种专门化只与实际的派生类不匹配CRTPBase<Derived>.我想要的是一种编写部分特化的方法,Derived当且仅当它来源于CRTPBase<Derived>.我的伪代码是
namespace std { namespace tr1 {
template <typename Derived>
struct hash<typename boost::enable_if<std::tr1::is_base_of<CRTPBase<Derived>, Derived>,
Derived>::type>
{
size_t operator()(const CRTPBase<Derived> & base) const
{
return base.hash();
}
};
} }
Run Code Online (Sandbox Code Playgroud)
......但是,这并不工作,因为编译器不能告诉大家,enable_if<condition, Derived>::type是Derived.如果我可以更改std::tr1::hash,我只需添加另一个虚拟模板参数boost::enable_if,如enable_if文档所建议的那样,但这显然不是一个很好的解决方案.有没有解决这个问题的方法?我是否必须在每个unordered_set或 …
我正在尝试编写一个基于策略的宿主类(即一个继承自其模板类的类),其中一个扭曲,其中策略类也由宿主类进行模板化,以便它可以访问其类型.这可能有用的一个例子是策略(实际上像mixin一样使用),使用多态clone()方法扩充宿主类.这是我正在尝试做的最小例子:
template <template <class> class P>
struct Host : public P<Host<P> > {
typedef P<Host<P> > Base;
typedef Host* HostPtr;
Host(const Base& p) : Base(p) {}
};
template <class H>
struct Policy {
typedef typename H::HostPtr Hptr;
Hptr clone() const {
return Hptr(new H((Hptr)this));
}
};
Policy<Host<Policy> > p;
Host<Policy> h(p);
int main() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
遗憾的是,这不能编译,在我看来像循环类型依赖:
try.cpp: In instantiation of ‘Host<Policy>’:
try.cpp:10: instantiated from ‘Policy<Host<Policy> >’
try.cpp:16: instantiated from here
try.cpp:2: error: invalid use of incomplete type ‘struct …Run Code Online (Sandbox Code Playgroud) 我没有对问题的准确描述,所以我只是问这是否可能(如果是的话,其他一些信息会很棒).
程序员告诉我,你可以避免虚函数/多态导致的运行时开销.他说为了避免运行时开销,你可以在名为Curiously_recurring_template_pattern的模式中使用模板,它看起来像这样:
class Derived : public Base<Derived>
{
// ... implementation here
};
Run Code Online (Sandbox Code Playgroud)
这个奇怪的重复模板模式如何工作?
如何使用Curiously-Recurring-Template-Pattern替换正常的虚函数/多态?
我弄错了吗?
作为系统设计的一部分,我们需要实现工厂模式.结合Factory模式,我们还使用CRTP来提供一组基本功能,然后可以通过Derived类进行自定义.
示例代码如下:
class FactoryInterface{
public:
virtual void doX() = 0;
};
//force all derived classes to implement custom_X_impl
template< typename Derived, typename Base = FactoryInterface>
class CRTP : public Base
{
public:
void doX(){
// do common processing..... then
static_cast<Derived*>(this)->custom_X_impl();
}
};
class Derived: public CRTP<Derived>
{
public:
void custom_X_impl(){
//do custom stuff
}
};
Run Code Online (Sandbox Code Playgroud)
虽然这种设计很复杂,但它确实提供了一些好处.初始虚函数调用之后的所有调用都可以内联.派生类custom_X_impl调用也是有效的.
我编写了一个比较程序来比较使用函数指针和虚函数的类似实现(紧密循环,重复调用)的行为.这个设计为gcc/4.8与O2和O3取得了胜利.
然而,C++专家昨天告诉我,大型执行程序中的任何虚函数调用都需要一个可变的时间,考虑到缓存未命中,我可以使用C样式函数表查找和gcc函数列表来实现更好的性能.但是我仍然看到上面提到的示例程序的成本的2倍.
我的问题如下:1.大师的断言是真的吗?对于任何一个答案,我可以参考任何链接.2.我是否可以参考任何低延迟实现,有一个基类使用函数指针在派生类中调用自定义函数?3.有关改进设计的建议吗?
任何其他反馈总是受欢迎的.
请考虑下面的简单示例:
#include <iostream>
template <typename T>
class Base
{
public:
static constexpr int y = T::x;
};
class Derived : public Base<Derived>
{
public:
static constexpr int x = 5;
};
int main()
{
std::cout << Derived::y << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在g ++中,这可以很好地编译5并按预期打印.但是,在Clang中,它无法编译错误no member named 'x' in 'Derived'.据我所知,这是正确的代码.我正在做什么有什么问题,如果没有,有没有办法让这个工作在Clang?
我正试着绕着CRTP.有一些很好的资料来源,包括这个论坛,但我认为我对静态多态性的基础知识有些困惑.查看以下维基百科条目:
template <class T>
struct Base
{
void implementation()
{
// ...
static_cast<T*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
T::static_sub_func();
// ...
}
};
struct Derived : public Base<Derived>
{
void implementation();
static void static_sub_func();
};
Run Code Online (Sandbox Code Playgroud)
我理解这有助于我在派生类中使用不同的implementation()变体,有点像编译时虚函数.但是,我的困惑是我觉得我不能有像这样的功能
void func(Base x){
x.implementation();
}
Run Code Online (Sandbox Code Playgroud)
就像我使用普通继承和虚函数一样,由于Base被模板化,但我必须指定
func(Derived x)
Run Code Online (Sandbox Code Playgroud)
或使用
template<class T>
func(T x)
Run Code Online (Sandbox Code Playgroud)
那么CRTP实际上在这个上下文中给我带来了什么,而不是简单地在Derived :: Base中简单地隐藏/实现该方法?
struct Base
{
void implementation();
struct Derived : public Base
{
void implementation();
static void static_sub_func();
};
Run Code Online (Sandbox Code Playgroud) 有一种不太常见的C++习语,我过去常常使用过好几次.我似乎无法记住它是否有一个通常使用的名称来描述它.
它与mixins,CRTP和类型擦除有一定关系,但并不是特别相关.
当您想要向类添加一些实现时,会发现问题,但您不希望将它放在类或它派生的任何类中.这样做的一个原因可能是类可能是继承层次结构的一部分,其中实现应该只发生一次.
暂时搁置一些问题,例如层次结构是否应该具有具体的非叶类,或者在某些情况下是否可以选择虚拟继承,我知道在模板类中提供实现的一种解决方案来源于它的模板参数.然后,这允许您在创建实例时使用模板,但之后只能通过指针使用对象或引用其中一个基础(在松散的意义上,类型擦除的位置).
一个例子可能是你有一个侵入性引用计数.你的所有类都来自一个引用计数接口,但你只希望引用计数本身和引用计数方法的实现出现一次,所以你将它们放在派生模板中 - 让我们调用它ImplementsRC<T>.现在你可以像这样创建一个实例:
ConcreteClass* concrete = new ImplementsRC<ConcreteClass>();
Run Code Online (Sandbox Code Playgroud)
我正在掩盖诸如由多个模板化重载等组成的转发构造函数.
所以,希望我已经明确了成语是什么.现在回到我的问题 - 这个成语是否有一个被接受的,或者至少是一般使用的名字?
我有一个普通的旧CRPT(请不要因访问限制而分心 - 问题与他们无关):
template<class Derived>
class Base {
void MethodToOverride()
{
// generic stuff here
}
void ProblematicMethod()
{
static_cast<Derived*>(this)->MethodToOverride();
}
};
Run Code Online (Sandbox Code Playgroud)
像往常一样打算像这样使用:
class ConcreteDerived : public Base<ConcreteDerived> {
void MethodToOverride()
{
//custom stuff here, then maybe
Base::MethodToOverride();
}
};
Run Code Online (Sandbox Code Playgroud)
现在static_cast困扰我了.我需要一个向下投射(不是向上投射),所以我必须使用一个明确的演员.在所有合理的情况下,强制转换都是有效的,因为当前对象确实是派生类.
但是如果我以某种方式改变层次结构并且演员现在变得无效呢?
我可以以某种方式强制执行编译时检查,在这种情况下显式向下转换有效吗?
奇怪的重复模板模式可用于实现一种静态多态性.例如:
#include <iostream>
template<
class Derived
>
struct Base
{
static void print ( )
{
std::cout << Derived::number_to_print << '\n';
}
};
struct Derived final :
Base<
Derived
>
{
static constexpr unsigned int number_to_print = 27;
};
int main ( )
{
Derived::print();
}
Run Code Online (Sandbox Code Playgroud)
这表现得如预期和打印27.
现在,我想向基类添加检查以断言派生类满足某些要求.在上面给出的示例中,此类检查可以是:
#include <iostream>
#include <type_traits>
template<
class Derived
>
struct Base
{
// --- Checks begin
static_assert( std::is_same<
decltype(Derived::number_to_print),
unsigned int
>::value,
"static member `number_to_print' should be of type `unsigned int'" …Run Code Online (Sandbox Code Playgroud) 我对“奇怪的重复模板模式”的概念很陌生,我正在此处阅读有关其潜在用例的信息。
在那篇文章中,作者描述了一个简单的情况,其中我们有两个或多个具有一些通用功能的类:
class A {
public:
int function getValue() {...}
void function setValue(int value) {...}
// Some maths functions
void scale() {...}
void square() {...}
void invert() {...}
}
class B {
public:
double function getValue() {...}
void function setValue(double value) {...}
// Some maths functions
void scale() {...}
void square() {...}
void invert() {...}
}
Run Code Online (Sandbox Code Playgroud)
作者认为,我们可以使用 CRTP,而不是在每个类中重复通用功能:
template <typename T>
struct NumericalFunctions
{
void scale(double multiplicator);
void square();
void invert();
};
class A : public NumericalFunctions<A>
{ …Run Code Online (Sandbox Code Playgroud) c++ ×10
crtp ×10
templates ×3
c++11 ×1
c++14 ×1
casting ×1
clang ×1
class-design ×1
gcc ×1
idioms ×1
low-latency ×1
mixins ×1
policy ×1
polymorphism ×1
static-cast ×1
type-erasure ×1
upcasting ×1