这是一个场景:我想拥有一个可以拥有可变数量的mixins的宿主类(对于可变参数模板来说并不太难 - 请参阅http://citeseerx.ist.psu.edu/viewdoc/summary?doi = 10.1.1.103.144).但是,我也喜欢使用主机类参数化mixins,以便它们可以引用其公共类型(使用CRTP惯用法).当试图混合两者时出现问题 - 我不清楚正确的语法.例如,以下代码无法使用g ++ 4.4.1进行编译:
template <template<class> class... Mixins>
class Host : public Mixins<Host<Mixins>>... {
public:
template <class... Args>
Host(Args&&... args) : Mixins<Host>(std::forward<Args>(args))... {}
};
template <class Host> struct Mix1 {};
template <class Host> struct Mix2 {};
typedef Host<Mix1, Mix2> TopHost;
TopHost *th = new TopHost(Mix1<TopHost>(), Mix2<TopHost>());
Run Code Online (Sandbox Code Playgroud)
有错误:
tst.cpp: In constructor ‘Host<Mixins>::Host(Args&& ...) [with Args = Mix1<Host<Mix1, Mix2> >, Mix2<Host<Mix1, Mix2> >, Mixins = Mix1, Mix2]’:
tst.cpp:33: instantiated from here
tst.cpp:18: error: type ‘Mix1<Host<Mix1, …
Run Code Online (Sandbox Code Playgroud) 我正在尝试将复制和交换习惯用法放入可重用的混音中:
template<typename Derived>
struct copy_and_swap
{
Derived& operator=(Derived copy)
{
Derived* derived = static_cast<Derived*>(this);
derived->swap(copy);
return *derived;
}
};
Run Code Online (Sandbox Code Playgroud)
我打算通过CRTP混合:
struct Foo : copy_and_swap<Foo>
{
Foo()
{
std::cout << "default\n";
}
Foo(const Foo& other)
{
std::cout << "copy\n";
}
void swap(Foo& other)
{
std::cout << "swap\n";
}
};
Run Code Online (Sandbox Code Playgroud)
但是,一个简单的测试显示它不起作用:
Foo x;
Foo y;
x = y;
Run Code Online (Sandbox Code Playgroud)
这仅打印两次"默认",不打印"复制"或"交换".我在这里错过了什么?
我编写了一个小型库,它使用了大量的C++ 11元编程技术和CRTP,它与g ++ 4.7.2编译得很好.
现在,我尝试使用Intel icpc 13.0.0.079进行编译,它会产生数百个错误.所以我试着一个接一个地隔离问题.
所以,首先,考虑一下在g ++ 4.7.2下编译没有问题的代码
#include <iostream>
template<template<typename> class Crtp, typename Type>
struct Base {};
template<typename Type>
struct Derived : public Base<Derived, Type>
{
Derived(): Base<Derived, Type>() {;}
};
int main()
{
Derived<int> x;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
icpc和clang都无法编译此代码:
test_crtp.cpp(26): error: type "Derived<Type>::Derived" is not a class template
Derived(): Base<Derived, Type>() {;}
^
test_crtp.cpp(26): error: "Base" is not a nonstatic data member or base class of class "Derived<int>"
Derived(): Base<Derived, Type>() {;}
^
detected during instantiation …
Run Code Online (Sandbox Code Playgroud) 我的团队正在开发一个嵌入式系统,我们需要遵循MISRA C++.
我们正在重构代码以使用更少的虚方法,因此我们尝试实现CRTP以使用静态多态而不是动态多态.
但是我们遇到静态多态性需要指针转换的问题,因此我们的静态分析检查器会抱怨.
这是界面
template <typename T>
class UpdateMethod
{
protected:
~UpdateMethod() {}
public:
void operator()() const
{
// [MISRA Rule 5-2-7] violation:
static_cast<const T*>(this)->update();
}
};
Run Code Online (Sandbox Code Playgroud)
以下是其中一个实现:
class A
: public UpdateMethod<A>
{
public:
void update() const {}
};
Run Code Online (Sandbox Code Playgroud)
在通过MISRA检查程序时,它会抱怨static_cast(从ptr转换为ptr(e926).
所以,我的问题是:有没有什么好的方法来实现CRTP而不必压制MISRA警告,所以以安全的方式?
仅有关于指针转换的相关问题: MISRA C++ 2008规则5-2-7违规:指针类型的对象不应直接或间接转换为无关指针类型 我在CRTP中具有相同的错误.
编辑:正如前面提到的只有C++ 03而没有像boost这样的外部库.
前段时间我想创建自己的数据映射器,它比平均ORM简单得多.这样做我发现需要访问我的基类中继承类的类型信息.我的第一个想法是反射,但它太慢了(如果你使用反射,请查看Fasterflect,因为它"几乎"消除了反射的性能问题).
所以我转向了一个解决方案,我后来发现它有自己的名字:奇怪的重复模板模式.这主要解决了我的问题,但学习如何正确实现这种模式有点挑战.我必须解决的两个主要问题是:
1)如何让我的消费代码与我的通用对象一起使用而无需知道创建对象的通用参数?
2)如何在C#中继承静态字段?
具有挑战性的部分实际上是在弄清问题.一旦我意识到我需要做什么,解决这些问题就很容易了.如果你发现自己需要CRTP,你可能会发现自己需要回答这些问题......它们似乎是相辅相成的.
我想将CRTP模式与一些锁定机制结合使用,以便在多线程环境中进行访问同步.
我的代码看起来像这样:
//-- CRTP base class with some sync/lock mechanism
template<typename T, typename SYNC>
struct Base {
static std::unordered_map<int, std::string> s_map;
static SYNC s_sync;
};
//-- derived class using CRTP
template<typename SYNC>
struct ProductX : public Base<ProductX<SYNC>, SYNC> {};
//-- static initialisation
template<typename SYNC>
std::unordered_map<int, std::string> Base<ProductX<SYNC>, SYNC>::s_map {
{ 1, "value_1" },
{ 2, "value_2" }
}
Run Code Online (Sandbox Code Playgroud)
但是我得到了
错误:非模板的模板定义
std::unordered_map<int, std::basic_string<char> > Base<ProductX<SYNC>, SYNC>::s_map
编译时
静态s_map
初始化引发错误.有人能指出我做错了什么吗?
简要:
我想确保派生类实现父CRTP类中的函数所需的成员函数.
详情:
我有一些像这样的代码
class Base
{
public:
class Params
{
public:
virtual ~Params() {}
};
virtual void myFunc( Params& p ) = 0;
};
template< typename T >
class CRTP : public Base
{
public:
virtual void myFunc( Base::Params& p ) override
{
typename T::Params& typedParams = dynamic_cast<typename T::Params&>( p );
static_cast<T*>( this )->myFunc( typeParams );
}
};
class Imp : public CRTP<Imp>
{
public:
class Params : public CRTP<Imp>::Params
{
public:
virtual ~Params() {}
int x, y, z; …
Run Code Online (Sandbox Code Playgroud) 考虑一下:
template<typename T>
struct base_t
{
auto& f(int x) { return (T&)*this; }
auto& f(char x) { return (T&)*this; }
};
struct derived_t : base_t<derived_t>
{
};
void test()
{
derived_t instance;
auto lambda = [&](derived_t&(derived_t::*g)(char))
{
(instance.*g)('a');
//instance.f('a');
};
lambda(&derived_t::f);
}
Run Code Online (Sandbox Code Playgroud)
没有在该特定行 ( //instance.f('a');
) 中发表评论,我收到以下错误 (MSVC 2019):
error C2664: 'void test::<lambda_1>::operator ()(derived_t &(__cdecl derived_t::* )(char)) const': cannot convert argument 1 from 'overloaded-function' to 'derived_t &(__cdecl derived_t::* )(char)'
Run Code Online (Sandbox Code Playgroud)
当该行没有被注释掉时,它编译得很好。
为什么引用f
insidelambda
神奇地允许编译器转换这个重载函数?
此外,如果没有 CRTP,这根本不会发生。
编辑:此外,正如@Jarod42 所指出的,
明确返回类型 …
作为系统设计的一部分,我们需要实现工厂模式.结合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.有关改进设计的建议吗?
任何其他反馈总是受欢迎的.
我有一个非常简单的 CRTP 骨架结构,其中仅包含一个向量和基类中的一个私有访问器。CRTP 类中有一个辅助方法可以访问它。
#include <vector>
template<typename T>
class CRTPType {
// Will be used by other member functions. Note it's private,
// so declval/decltype expressions outside of friends or this class
// cannot see it
auto& _v() {
return static_cast<T *>(this)->getV();
}
};
class BaseType : public CRTPType<BaseType> {
friend class CRTPType<BaseType>;
std::vector<int> v;
//For different base types this impl will vary
auto& getV() { return v; }
};
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都很好。现在我想添加一个using
声明,CRTPType
该声明将是返回的类型_v()
。因此,理想情况下,人们可以执行如下操作:
template<typename T>
class …
Run Code Online (Sandbox Code Playgroud) crtp ×10
c++ ×8
c++11 ×3
mixins ×2
templates ×2
c# ×1
c++03 ×1
c++14 ×1
c++17 ×1
class-design ×1
g++ ×1
gcc ×1
lambda ×1
low-latency ×1
misra ×1
overloading ×1
static-cast ×1
variadic ×1