当前位置:  开发笔记 > 编程语言 > 正文

C++模板:按类分类,如何分解代码?

如何解决《C++模板:按类分类,如何分解代码?》经验,为你挑选了2个好方法。

假设我有这个课程:

class Component1;
class Component2;
// many different Components
class Component42;

class MyClass
{
public:
    MyClass(void) {};
    std::list component1List;
    std::list component2List;
    // one list by component
    std::list component42List;
};

我想创建一个具有以下签名的函数:

template void addElement(T component);

它应该做到以下几点:

如果component是类型Component1,请将其添加到Component1List

if component是类型Component2,添加到Component2List,等等.

可能吗?这样做的好方法是什么?

我可以通过以下函数获得相同的行为:

template void addElement(int componentType, T component);

但我宁愿不必指定componentType这样的:它是无用的信息,它打开了可能的错误的大门(如果componentType不代表组件的类型).



1> Richard Hodg..:

std::tuple 救援.

更新日志:

使用 std::decay_t

添加了可变参数形式

add_component() 现在返回对此的引用以允许调用链接.


#include 
#include 
#include 
#include 
#include 

class Component1 {};
class Component2 {};
struct Component3 {
    Component3() {}
};
// many different Components

template
class MyClassImpl
{
    template using list_of = std::list;

public:

    using all_lists_type =
    std::tuple<
    list_of ...
    >;


    // add a single component
    template
    MyClassImpl& add_component(Component&& c)
    {
        list_for().push_back(std::forward(c));
        return *this;
    }

    // add any number of components
    template
    MyClassImpl& add_components(Components&&... c)
    {
        using expand = int[];
        void(expand { 0, (void(add_component(std::forward(c))), 0)... });
        return *this;
    }



    template
    auto& list_for()
    {
        using component_type = std::decay_t;
        return std::get>(_lists);
    }

    template
    const auto& list_for() const
    {
        using component_type = std::decay_t;
        return std::get>(_lists);
    }


private:

    all_lists_type _lists;
};

using MyClass = MyClassImpl;

int main()
{
    MyClass c;

    c.add_component(Component1());
    c.add_component(Component2());

    const Component3 c3;
    c.add_component(c3);

    c.add_components(Component1(),
                     Component2(),
                     Component3()).add_components(Component3()).add_components(Component1(),
                                                                               Component2());

    std::cout << c.list_for().size() << std::endl;

    return 0;
}



2> Ulrich Eckha..:

最直接的变体是简单地不使用模板而是重载addElement()函数:

void addElement(Component1 element)
{
    this->element1List.push_back(element);
}
void addElement(Component2 element)
{
    this->element2List.push_back(element);
}
// ... etc

但是,如果你有很多这样的话,这可能会很乏味(addElement()我猜你不会这样做).使用宏来生成每种类型的代码仍然可以通过合理的努力完成工作.

如果您真的想使用模板,可以使用模板功能并为每种类型专门设置模板功能.但是,与上述方法相比,这并没有减少代码重复的数量.此外,您仍然可以使用宏来生成代码来减少它.

但是,希望以通用方式执行此操作.首先,让我们创建一个包含列表的类型:

template
struct ComponentContainer
{
    list componentList;
};

现在,派生类只是继承自这个类,并使用C++类型系统来定位正确的容器基类:

class MyClass:
    ComponentContainer,
    ComponentContainer,
    ComponentContainer
{
public:
    template
    void addElement(T value)
    {
        ComponentContainer& container = *this;
        container.componentList.push_back(value);
    }
}

注意:

这使用私有继承,这与您最初使用的包含非常相似.

即使ComponentContainer是基类,它也没有任何虚函数,甚至也没有虚析构函数.是的,这很危险,应该清楚地记录下来.我不会添加虚拟析构函数,因为它具有开销,因为它不应该被需要.

您可以完全放弃中间容器list,也可以从中获取.我没有,因为它会使所有list的成员函数在课堂上可用MyClass(即使不公开),这可能会令人困惑.

您不能将该addElement()函数放入基类模板中以避免派生类中的模板.原因很简单,扫描不同的基类以便执行addElement()功能,然后才执行重载决策.编译器只会addElement()在第一个基类中找到它.

这是一个简单的C++ 98解决方案,对于C++ 11,我会看一下Jens和Richard建议的基于类型的元组查找解决方案.

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有