我有一个类,我试图配置它的行为.
template<int ModeT, bool IsAsync, bool IsReentrant> ServerTraits;
Run Code Online (Sandbox Code Playgroud)
然后我有我的服务器对象本身:
template<typename TraitsT>
class Server {...};
Run Code Online (Sandbox Code Playgroud)
我的问题是我上面的用法是我的命名错误吗?我的模板化参数实际上是一个策略而不是特征吗?
什么是模板化论证的特征与政策相比?
c++ type-traits policy-based-design template-meta-programming
struct InkPen
{
void Write()
{
this->WriteImplementation();
}
void WriteImplementation()
{
std::cout << "Writing using a inkpen" << std::endl;
}
};
struct BoldPen
{
void Write()
{
std::cout << "Writing using a boldpen" << std::endl;
}
};
template<class PenType>
class Writer : public PenType
{
public:
void StartWriting()
{
PenType::Write();
}
};
int main()
{
Writer<InkPen> writer;
writer.StartWriting();
Writer<BoldPen> writer1;
writer1.StartWriting();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我将上述代码编写为学习基于策略的设计的一部分.我对上面的代码几乎没有疑问
1 - 此实现看起来是否正确?我的意思是:它真的看起来像一个基于政策的设计吗?
2 - 我现在可以将任何类型的笔钩到作家身上.但是当我拿到没有默认构造函数的笔(仅参数化构造函数)时,我会怎么做?我该如何处理这种情况?
template<class PenType>
class Writer : public PenType …Run Code Online (Sandbox Code Playgroud) 我正在构建一个矩阵库,我正在尝试使用基于策略的设计.所以我的基类是提供存储方法和一些访问功能的类.我还有一个提供数学函数的函数矩阵.这很好用,但由于返回类型,运算符*存在一个主要问题.我将用一些代码解释它.
提供堆栈存储的基类:
template < typename T, unsigned int rows, unsigned int cols>
class denseStackMatrix {
public:
typedef T value_type;
private:
value_type grid[rows][cols];
const unsigned int rowSize;
const unsigned int colSize;
Run Code Online (Sandbox Code Playgroud)
然后我有我的矩阵类,它提供了数学功能:
template <typename MatrixContainer >
class matrix : public MatrixContainer {
public:
typedef MatrixContainer Mcontainer;
matrix<Mcontainer>& operator +(const matrix<Mcontainer>&);
matrix<Mcontainer>& operator *(const matrix<Mcontainer>&);
Run Code Online (Sandbox Code Playgroud)
operator+总是有效,operator*只适用于方阵.所以我们仍然需要一个所有矩阵.这就是它出错了.我已经尝试了很少的东西,但没有尝试.我寻找这样的东西,在c ++ 0x的帮助下(c ++ 0x的使用不是必需的)你应该注意到"???" :)
friend auto operator * (const matrix<T1>& matrix1, const matrix<T2>& matrix2)
-> decltype(matrix<???>);
Run Code Online (Sandbox Code Playgroud)
问题的一个例子
matrix<denseStackMatrix<int,3,2> > matrix1; …Run Code Online (Sandbox Code Playgroud) 我读到了"现代C++设计"中的类型列表,我将其理解为某种类型的联合.通过在类型列表中放置不同的,不相关的类型,可以使用它一次表示多个类型,而无需继承.我在原始类型的一些简单函数中测试了类型列表,但我无法使它们中的任何一个工作.
有人可以告诉我,如果我对类型列表的解读是正确的,并给出一个简单的现实世界的例子,如何在每天的平均代码中使用类型列表?提前致谢.
顺便说一下,我正在使用Windows和Visual Studio 2005及其编译器.
编辑:我的例子不见了,我在vs中使用沙箱项目来测试这些东西.但它很安静,类似于Dobbs教程中的代码:
void SomeOperation(DocumentItem* p)
{
if (TextArea* pTextArea = dynamic_cast<TextArea*>(p))
{
... operate on a TextArea object ...
}
else if (VectorGraphics* pVectorGraphics =
dynamic_cast<VectorGraphics*>(p))
{
... operate on a VectorGraphics object ...
}
else if (Bitmap* pBitmap = dynamic_cast<Bitmap*>(p))
{
... operate on a Bitmap object ...
}
else
{
throw "Unknown type passed";
}
}
Run Code Online (Sandbox Code Playgroud)
这有效,但我没有看到继承能够做到这一点的优势.动态转换不适用于基本类型.是否可以将其用作返回值,如:
typedef Typelist<int, string> mylist
mylist myfunction() {
if(foo == bar)
return 5;
return "five";
}
Run Code Online (Sandbox Code Playgroud) 更新:我在这里问了一个较窄的问题.
在现代C++设计的第6-7页,Andrei Alexandrescu 就构建灵活设计两个C++语言特性(多重继承和模板)的优缺点进行了非常基础的讨论.他的结论是:
现在将多重继承的缺点列表与模板的缺点列表进行比较.有趣的是,多重继承和模板促进了互补的权衡.多重遗传有很少的机制; 模板有丰富的机制.多重继承会丢失模板中充斥的类型信息.模板的专业化不能扩展,但多重继承可以很好地扩展.您只能为模板成员函数提供一个默认值,但您可以编写无限数量的基类.
我能感觉到安德烈在这里所说的非常重要,但我无法真正理解所说的内容,没有任何例子来说明这些要点.这个问题要求提供简单的例子来说明这些要点(请继续阅读).
为了使问题更具体,我想请您关注多重继承的弱点.这就是安德烈对他们所说的话(根据我对上下文的理解,方括号中的文字是我的):
在这样的设置[即多重继承 ],[构建一个灵活的
SmartPtr],用户将通过继承一些BaseSmartPtr类和两个类来构建一个多线程,引用计数的智能指针类:MultiThreaded和RefCounted.任何经验丰富的班级设计师都知道这种天真的设计不起作用.分析多重继承无法创建灵活设计的原因,为获得完善的解决方案提供了有趣的思路.使用多重继承来组装单独功能的问题如下:
- 力学.没有样板代码以受控方式组装继承的组件.组合BaseSmartPtr,MultiThreaded和RefCounted的唯一工具是一种称为多重继承的语言机制.该语言在组合基类时应用简单的叠加,并建立一组用于访问其成员的简单规则.除最简单的情况外,这是不可接受的.大多数情况下,您需要仔细编排继承类的工作方式以获得所需的行为.
- 输入信息.基类没有足够的类型信息来执行其任务.例如,假设您尝试通过从DeepCopy基类派生来为智能指针类实现深层复制.但是DeepCopy有什么接口?它必须创建一个它不知道的类型的对象.
- 国家操纵.使用基类实现的各种行为方面必须操纵相同的状态.这意味着它们必须使用虚拟继承来继承保存状态的基类.这使设计复杂化并使其更加严格,因为前提是用户类继承库类,反之亦然.
我非常感谢上面三个项目中的每个项目的简单示例.每个例子都会显示多重继承的一个限制(例如,差的机制)以及模板如何不具备这种限制(Andrei写道" 多重继承和模板促进互补权衡").
在阅读了一篇关于基于策略的设计并希望自己尝试一些内容的文章后,我花了一些时间重新设计一个记录器类,我曾做过一次基于策略的方法.
一些代码:
template <class Filter, class Formatter, class Outputter>
class LoggerImpl : public LoggerBase {
public:
LoggerImpl(const Filter& filter = Filter(), const Formatter& formatter = Formatter(), const Outputter& outputter = Outputter());
~LoggerImpl();
void log(int channel, int loglevel, const char* msg, va_list list) const;
private:
const Filter mFilter;
const Formatter mFormatter;
const Outputter mOutputter;
};
template <class Filter, class Formatter, class Outputter>
LoggerImpl<Filter, Formatter, Outputter>::LoggerImpl(const Filter& filter, const Formatter& formatter, const Outputter& outputter) :
mFilter(filter), mFormatter(formatter), mOutputter(outputter) {
debuglib::logdispatch::LoggerMgr.addLogger(this);
}
typedef …Run Code Online (Sandbox Code Playgroud) 考虑一个基于策略的智能指针类Ptr,只有一个策略可以防止在NULL状态下解除引用它(不知何故).让我们考虑两种这样的政策:
NotNullNoChecking由于NotNull政策限制较多,我们希望允许隐式转换Ptr< T, NoChecking >到Ptr< T, NotNull >,但不能在相反的方向.那一个必须明确安全.请看一下以下实现:
#include <iostream>
#include <type_traits>
#include <typeinfo>
struct NoChecking;
struct NotNull;
struct NoChecking{
NoChecking() = default;
NoChecking( const NoChecking&) = default;
explicit NoChecking( const NotNull& )
{ std::cout << "explicit conversion constructor of NoChecking" << std::endl; }
protected:
~NoChecking() {} //defaulting the destructor in GCC 4.8.1 makes it public somehow :o
};
struct NotNull{
NotNull() = default;
NotNull( const NotNull&) = default;
NotNull( const NoChecking& …Run Code Online (Sandbox Code Playgroud) c++ constructor policy-based-design implicit-conversion c++11
在 Meeting C++ 2019 上,Jon Kalb 发表了关于模板技术的演讲,并提到了策略类。来源见这里:https : //youtu.be/MLV4IVc4SwI?t=1815
有问题的有趣代码片段是:
template<class T, class CheckingPolicy>
struct MyContainer : private CheckingPolicy
{
...
}
Run Code Online (Sandbox Code Playgroud)
我经常看到这种类型的设计,我想知道这里的继承是否比组合有任何真正的优势。在我的个人经验中,我听说过很多关于优先组合而不是继承范式的内容。所以我写代码的方式更像是这样:
template<class T, class CheckingPolicy>
struct MyContainer
{
CheckingPolicy policy;
...
}
Run Code Online (Sandbox Code Playgroud)
不会涉及任何虚拟功能。不过,如果您能分享一些见解,我将不胜感激。我对内存布局的差异及其影响特别感兴趣。如果CheckingPolicy没有数据成员,而只有check方法或重载的调用运算符,会有所不同吗?
我想对模板类使用部分特化,以便该模板类的所有子节点都将使用该特化.让我用一个例子来解释:)
template < typename T, unsigned int rows, unsigned int cols>
class BaseMatrix {...};
Run Code Online (Sandbox Code Playgroud)
这个类将有子项指定矩阵的结构,如稀疏,密集,对角线,..
template < typename T, unsigned int rows, unsigned int cols>
class DiagonalMatrix : public BaseMatrix<T,rows,cols>{..}
Run Code Online (Sandbox Code Playgroud)
然后这些类将再次生成指定存储的子节点:堆栈数组,向量,列表,队列,..
template < typename T, unsigned int rows, unsigned int cols>
class StackDiagonalMatrix : public DiagonalMatrix<T, rows, cols> {..}
Run Code Online (Sandbox Code Playgroud)
然后有一个类Matrix,它提供所有数学功能.这个模板类实现了operator +,operator-等......
template <typename T,
template<typename, unsigned, unsigned> class MatrixContainer,
unsigned Rows,
unsigned Cols>
class matrix;
Run Code Online (Sandbox Code Playgroud)
对于这最后一堂课,我想写下这样的专业:
template <typename T,unsigned Rows, unsigned Cols>
class matrix<T, BaseMatrix, Rows, Cols> {};
template <typename …Run Code Online (Sandbox Code Playgroud) 我有一组同类策略类,我想将它们作为策略传递给模板类PolicyDrivenClass,它采用一些未知数量的策略模板参数.
每个策略都实现了一个"名称"功能,我希望能够通过PolicyDriveClass :: getNames在运行时查询所有策略的名称.
我有一个工作实现,但它感觉笨重,特别是考虑到在我的最终设计中,Policy类将实现类似于"name"的几个函数,尽管可能具有不同的返回类型,并且我的Policy Driven Class将希望提供类似的访问器每个功能的"getNames".
我的问题是,是否有人能够为此提出更好的实施方案.
为什么它值得我使用clang ++.我的g ++版本不喜欢这个.
这是我到目前为止所拥有的:
#include <string>
#include <deque>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
template<typename... Policies>
class PolicyDrivenClass
{
public:
template<typename T, typename... Types>
class NameExtractor
{
public:
static deque<string> getNames()
{
deque<string> names = NameExtractor<Types...>::getNames();
names.push_front(T::name());
return names;
}
};
template<typename T>
class NameExtractor<T>
{
public:
static deque<string> getNames()
{
deque<string> ret;
ret.push_back(T::name());
return ret;
}
};
deque<string> getNames() const
{
return NameExtractor<Policies...>().getNames();
}
};
class Policy1
{ …Run Code Online (Sandbox Code Playgroud) c++ ×10
templates ×5
c++11 ×3
constructor ×1
inheritance ×1
logging ×1
ofstream ×1
type-traits ×1
typelist ×1