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

C++ 定义/使用从预设组件构建的类(在C+;+;),c++,C++,我试图设计一个系统,用户可以将自己的类定义为若干预定义组件的集合,然后让这个类使用我提供的算法。我尝试使用编译时和/或基于模板的方法来实现这一点,而不是运行时多态性或虚拟函数,因为在这种情况下,性能非常重要 例如,考虑到我有很多组件可以用来构建一个三维顶点。我将这些组件定义为位置、法线、颜色等,然后用户将能够(通过多重继承、合成或什么?)定义一个顶点,例如PositionAndColorVertex,它只有位置和颜色,但没有法线。现在,我提供一个函数,它对一百万个顶点的向量进行一些处理: tem

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

例如,考虑到我有很多组件可以用来构建一个三维顶点。我将这些组件定义为位置、法线、颜色等,然后用户将能够(通过多重继承、合成或什么?)定义一个顶点,例如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
}
模板
void myProvidedAlgorithm(标准::矢量输入)
{
if(顶点有一个位置)
//按职位办事
if(顶点有法线)
//做一些正常的事情
如果(顶点有颜色)
//用颜色做东西
}
现在,我不知道UsersVertexType会是什么样子,但它将由我的组件构建。我的函数需要对每个组件执行某些操作,但前提是它们存在。什么是一种优雅且快速(编译时)的表达方式

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

也许我的组件应该用C++的概念或策略来表达?我也看到过关于mixin的讨论,但不确定它们是否有用。users类应该使用多重继承还是复合?也许我应该在users类中设置一组标志,指示它包含什么?你将如何设计这个系统

谢谢你的洞察力


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

通常的模式是使用
type\u traits
,和/或使用可专门用于UserVertexType的独立函数模板

添加一点SFINAE重载选择魔法,瞧:你已经发明了模板元编程和Boost图形库

小创意示例:

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&);
模板
结构顶点特征//默认顶点特征:
{
typename未使用的标签位置类型;
枚举{
hasNormal=0//视为“布尔”
hasColor=0
}; 
};
模板顶点特征::位置类型和位置(V&);
其思想是,通过在类之外定义泛型内容,您不会对用户选择顶点类型施加任何不必要的限制(他们可以只使用std::pair,他们可能只传递第三方类型并将其修饰为与图形库一起使用等)


Google:“非成员函数如何改进封装”(Scott Meyer)

特性和模板专门化

#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"; }
};
模板
构造一些位置;
模板结构的某些位置{

void运算符()(){std::cout重新发明Boost Graph Library?在用户类上设置标志听起来是个好主意。一个单独的额外变量包含或检查每个元素的标志,或者更好,如果您正在检查标志的组合,则直接检查数字。好的,这是很好的信息。以及您提供的BGL/Meyers链接,我也来了这也是一个基于特征的方法。我将进一步研究这些。好的,谢谢,我想我可以使用这样的方法。sehe的答案在使用特征方面也是正确的,但我会接受这是一个更完整的例子。
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());
}