0

我有以下情况:

template <typename T>
class Derived
{
public:
    T m_Data;
};

我需要将它们存储起来,std::vector所以我引入了一个抽象父类,如下所示:

class Base
{
public:
  virtual unsigned int GetID() const = 0;
};

Derived继承自Base

template <typename T>
class Derived : public Base
{
public:
    T m_Data;
    unsigned int GetID() const override
    {
        return something;
    }
}

所以现在我可以std::vector像这样存储它们:

std::vector<Base*> m_Bases;

现在在程序执行的某个时刻,我需要迭代m_Bases并根据某些条件选择一些并使用它们各自的m_Data,如下所示:

void Foo()
{
    for (auto& b : m_Bases)
    {
        if (some_condition)
        {
            // Access b->m_Data
        }
    }
}

由于我不能这样做,因为T m_Datais member of Derivedand not Base,所以我引入了一个访问者向量:

std::vector<std::function<void(Base*, std::function<void(std::any)>&)>> m_DerivedVisitors;

现在,当我插入一个新Derived<T>的时,m_Bases我也会插入一个新的 lambda,m_DerivedVisitors这样我以后可以像这样调用:

template <typename T>
void CreateBase()
m_Bases.push_back(new Derived<T>());
m_DerivedVisitors.push_back([](Base* base, auto visitor)
{
    if (dynamic_cast<Derived<T>*>(base) != nullptr)
    {
        visitor(static_cast<Derived<T>*>(base));
    }
});

现在Foo可能会Derived在访问者通用 lambda(我希望)中获得一个实例,如下所示:

void Foo()
{
    for (auto& b : m_Bases)
    {
        if (some_condition)
        {
            // Access b->m_Data
            // Note that I made sure GetID() is returning counting index based on template instantiation 
            // So I could use it to index into m_Bases as-well as into m_DerivedVisitors
            m_DerivedVisitors[b->GetID()](base, [&](auto derivedPtr) {
                // Now I can access derivedPtr->m_Data and use outside variable with capture list
            });
        }
    }
}

现在,如果您有敏锐的眼光,您会发现这段代码存在一些问题。
我不知道第二个参数m_DerivedVisitors应该是什么类型。
现在它设置为,std::function<void(std::any)>&因为我不知道访问者的类型,因为它的参数应该是Derived模板类型,所以我尝试使用std::any 并且对于访问者本身,我使用了一个auto参数,使其成为通用 lambda:

std::vector<std::function<void(Base*, std::function<void(std::any)>&)>> m_DerivedVisitors;
...
            m_DerivedVisitors[b->GetID()](base, [&](auto derivedPtr) {
                // Now I can access derivedPtr->m_Data and use outside variable with capture list
            });
...

我不确定如何使它工作。
如果有人能用代码示例解释如何做到这一点,我将不胜感激。

提前致谢。

更新:
我想到了一个我根本不喜欢的解决方案,但无论如何我都会提出,也许它可以帮助某人帮助我改进它或找到另一个解决方案。我们改成m_DerivedVisitors这样:

std::vector<std::function<void(Base*)>> m_DerivedVisitors;

我们像这样推动它:

m_DerivedVisitors.push_back([](Base* base)
{
    if (dynamic_cast<Derived<T>*>(base) != nullptr)
    {
        Visit(static_cast<Derived<T>*>(base));
    }
});

注意我们刮掉了auto visitor函数参数,我们现在调用一个静态 Visit方法,定义如下:

template<typename U>
static inline void Visit(U* object)
{
    auto x = object->m_Data;
    // Now we can do what ever we like with m_Data
}

我在这个解决方案中看到的问题是我无法具体说明我使用的访问者。解决此问题的一种方法是m_DerivedVisitors再次更改为以下内容:

std::vector<std::function<void(Base*, unsigned int)>> m_DerivedVisitors;

并像这样改变我们推送它的方式:

m_DerivedVisitors.push_back([](Base* base, unsigned int id)
{
    if (dynamic_cast<Derived<T>*>(base) != nullptr)
    {
        switch(id)
        {
        case 0:
            Visit0(static_cast<Derived<T>*>(base));
            break;
        case 1:
            Visit1(static_cast<Derived<T>*>(base));
            break;
        ...
        };
    }
});

如您所见,我们必须将所有访问者定义为静态函数,并且我们必须使用id. 我们甚至不能这样做,std::unordered_map因为我们不能std::function指向模板函数。

现在,每当有东西想将派生类型用于特定任务时,我们都必须定义一个静态函数并将其添加到 switch case 并使用适当的id.

这不是唯一的问题。
最初在我的代码Foo中给出了一个模板 lambda 参数以及我想传递m_Data给它的方法,方法如下:

template <typename Fn>
void Foo(Fn&& fn)
{
    for (auto& b : m_Bases)
    {
        if (some_condition)
        {
            // Access b->m_Data and pass it to fn
            fn(b->m_Data); // Note this doesn't compile; just to demonstrate my intentions
        }
    }
}

现在,为了使用我提出的解决方案来做到这一点,我必须存储fn一些静态/全局变量并在访问者函数中访问它,如下所示:

static int y = 8;

template<typename U>
static inline void Visit0(U* object)
{
    // access y
    auto x = object->m_Data;
}

template <typename Fn>
void Foo(Fn&& fn)
{
    for (auto& b : m_Bases)
    {
        if (some_condition)
        {
            // Access b->m_Data and pass it to fn
            y = 5;
            m_DerivedVisitors[b->GetID()](b, 0);
        }
    }
}

请注意,这不适用于捕获模板类型,Fn&& fn因为我不能拥有该类型的静态/全局变量,因为它完全是一个不同的范围。更不用说对于想要将其他变量引入访问函数的每种访问者,我都必须这样做,那是因为我不能像我最初的计划那样将 lambda 与捕获列表一起使用。

所以你可以看到这个解决方案根本不理想,它只是一个想法。
希望有人能想到更好的方法或指导我做其他事情。

4

0 回答 0