定义/使用从预设组件构建的类(在C ++中)

时间:2011-12-23 10:35:15

标签: c++

我正在尝试设计一个系统,用户可以将自己的类定义为许多预定义组件的集合,然后让这个类与我提供的算法一起工作。我试图用编译时和/或基于模板的方法来做这个,而不是运行时多态或虚函数,因为在这种情况下性能很重要。

例如,考虑我有许多可用于构建3D顶点的组件。我将这些组件定义为Position,Normal,Color等,然后用户将能够(通过多重继承,组合或什么?)来定义一个顶点,例如PositionAndColorVertex,它只有位置和颜色但没有法线。现在,我提供了一个函数,它对一百万个这些顶点的向量进行一些处理:

template<typename UsersVertexType>
void myProvidedAlgorithm(std::vector<UsersVertexType> input)
{
    if(vertex has a position)
        //do stuff with position
    if(vertex has a normal)
        //do stuff with normal
    if(vertex has a color)
        //do stuff with color
}

现在,我不知道UsersVertexType会是什么样子,但它将从我的组件构建。我的函数需要对每个组件执行某些操作,但前提是它们存在。什么是表达这种优雅和快速(编译时)的方式?

当然,我可以为每种类型定义一个基类,让用户从所需的基类继承,然后使用dynamic_cast来检查实现了哪些组件,但这正是我想要的那种运行时方法避免。也许我可以在编译时检查这个继承关系(编译器应该知道UsersVertexType实际上是什么,对吧?)。

也许我的组件应该使用C ++概念或策略来表达?我也看到了关于mixins的讨论,但不确定这些是否有用。用户类应该使用多重继承还是组合?也许我应该以某种方式在users类中获得一组标志,指出它包含什么?你会如何设计这个系统?

感谢您的任何见解!

注意:previous question有相似之处,但在这里我退后一步,寻找更高级别的设计选项/备选方案。

2 个答案:

答案 0 :(得分:4)

通常的模式是使用type_traits,和/或使用可以专用于UserVertexType的独立函数模板。

添加一些SFINAE过载选择魔法和瞧:你发明了模板元编程和Boost Graph Library。

小想法样本:

template <typename VertexType>
struct vertex_traits // default vertex_traits:
{
    typename unused_tag position_type;
    enum { 
        hasNormal = 0 // treat as 'boolean'
        hasColor = 0 
    }; 
};

template <typename V> vertex_traits<V>::position_type& position(V&);

这个想法是,通过将通用的东西定义在外面这个类,你不会对用户选择的顶点类型施加任何不必要的限制(他们可能只是使用std :: pair,他们可能只是传递第三方类型并将其装饰以用于您的图库等。)

Google:&#34;非会员功能如何改善封装&#34; (作者Scott Meyer)

答案 1 :(得分:2)

特征和模板专业化。

#include <iostream>
template <typename V> struct traits; // Primary template.

然后为具有位置分量的顶点定义一个版本,为没有的顶点定义一个版本:

template <typename Vertex, bool has_position=traits<Vertex>::has_position> 
struct some_position_op;

template <typename Vertex> struct some_position_op<Vertex,false> {
    void operator() () { std::cout << "has no position.\n"; }
};

template <typename Vertex> struct some_position_op<Vertex,true> {
    void operator() () { std::cout << "has position.\n"; }
};

最后,对于您定义的每个顶点类型,实现一个traits类:

struct MyVertexWithPosition {};
template <> 
struct traits<MyVertexWithPosition> {
    static constexpr bool has_position = true;
};


struct MyVertexWithoutPosition {};
template <> 
struct traits<MyVertexWithoutPosition> {
    static constexpr bool has_position = false;
};

......玩得开心:

template <typename Vertex>
void shade (Vertex const &vtx) {
    some_position_op<Vertex>() ();
}

int main () {
    shade (MyVertexWithPosition());
    shade (MyVertexWithoutPosition());
}

你也可以专门化功能模板,但必须牺牲shade功能的一些可读性。