我有点困惑。我有一个模板类 graph
带有模板参数 - 类 vertex
,可以是对称的或非对称的,压缩的或原始的,我只在运行时知道是哪个。
因此,如果我想从磁盘获取适当类型的图形,在其上运行 Bellman Ford,然后释放内存,我需要在所有四个条件分支中重复模板实例化,如下所示:
#include "graph.h"
int main(){
// parse cmd-line args, to get `compressed` `symmetric`
// TODO get rid of conditionals.
if (compressed) {
if (symmetric) {
graph<compressedSymmetricVertex> G =
readCompressedGraph<compressedSymmetricVertex>(iFile, symmetric,mmap);
bellman_ford(G,P);
} else {
graph<compressedAsymmetricVertex> G =
readCompressedGraph<compressedAsymmetricVertex>(iFile,symmetric,mmap);
bellman_ford(G,P);
if(G.transposed) G.transpose();
G.del();
}
} else {
if (symmetric) {
graph<symmetricVertex> G =
readGraph<symmetricVertex>(iFile,compressed,symmetric,binary,mmap);
bellman_ford(G,P);
G.del();
} else {
graph<asymmetricVertex> G =
readGraph<asymmetricVertex>(iFile,compressed,symmetric,binary,mmap);
bellman_ford(G,P);
if(G.transposed) G.transpose();
G.del();
}
}
return 0;
}
问题:除了对 readGraph
的调用之外,我如何提取所有内容?在具有以下限制的条件之外运行。
- 我无法修改图表模板。否则我会简单地将 Vertex 类型移动到 union 中。
- 我不能使用
std::variant
因为graph<T>
不能默认构造。 - 通话开销是个问题。如果有不涉及制作的基于子类型多态性的解决方案
compressedAsymmetricVertex
vertex
的子类型,我洗耳恭听。
编辑:这是一个示例标题 graph.h
:
#pragma once
template <typename T>
struct graph{ T Data; graph(int a): Data(a) {} };
template <typename T>
graph<T> readGraph<T>(char*, bool, bool, bool) {}
template <typename T>
graph<T> readCompressedGraph<T> (char*, bool, bool) {}
class compressedAsymmetricVertex {};
class compressedSymmetricVertex {};
class symmetricVertex{};
class asymmetricVertex {};
最佳答案
由于你没有把所有的类型都说出来,也没有解释binary
参数是怎么回事,所以我只能给出一个大概的方案。根据您的确切需求对其进行优化。这应该符合:
class GraphWorker
{
public:
GraphWorker(bool compressed, bool symmetric)
: m_compressed(compressed), m_symmetric(symmetric)
{}
virtual void work(const PType & P, const char * iFile, bool binary, bool mmap ) const = 0;
protected:
const bool m_compressed;
const bool m_symmetric;
};
template <class GraphType>
class ConcreteGraphWorker : public GraphWorker
{
public:
ConcreteGraphWorker(bool compressed, bool symmetric)
: GraphWorker(compressed, symmetric)
{}
void work(const PType & P, const char * iFile, bool binary, bool mmap) const override
{
graph<GraphType> G =
readGraph<GraphType>(iFile, m_compressed, m_symmetric,
binary, mmap);
bellman_ford(G,P);
G.del();
}
};
static const std::unique_ptr<GraphWorker> workers[2][2] = {
{
std::make_unique<ConcreteGraphWorker<asymmetricVertex>>(false, false),
std::make_unique<ConcreteGraphWorker<symmetricVertex>>(false, true),
},
{
std::make_unique<ConcreteGraphWorker<compressedAsymmetricVertex>>(true, false),
std::make_unique<ConcreteGraphWorker<compressedSymmetricVertex>>(true, true),
}
};
int main()
{
workers[compressed][symmetric]->work(P, iFile, binary, mmap);
}
一些评论:最好完全避免bool
,而使用特定的枚举类型。这意味着您应该使用类似以下内容的内容,而不是我的二维数组:
std::map<std::pair<Compression, Symmetry>, std::unique_ptr<GraphWorker>> workers;
但由于可能存在其他未知依赖项,我决定坚持使用令人困惑的 bool
变量。此外,将 workers
作为静态变量也有其缺点,并且由于我不知道您的其他要求,所以我不知道如何处理它。另一个问题是基类中 protected bool 变量。通常,我会改用访问器。
我不确定为了避免几个条件语句而进行的所有这些跳来跳去是否值得。这比原始代码长得多且更复杂,除非有超过 4 个选项,或者 work()
中的代码长得多,否则我建议坚持使用条件。
编辑:我刚刚意识到使用 lambda 函数可以说更清晰(有待商榷)。在这里:
int main()
{
using workerType = std::function<void(PType & P, const char *, bool, bool)>;
auto makeWorker = [](bool compressed, bool symmetric, auto *nullGrpah)
{
auto worker = [=](PType & P, const char *iFile, bool binary, bool mmap)
{
// decltype(*nullGraph) is a reference, std::decay_t fixes that.
using GraphType = std::decay_t<decltype(*nullGrpah)>;
auto G = readGraph<GraphType>(iFile, compressed, symmetric,
binary, mmap);
bellman_ford(G,P);
G.del();
};
return workerType(worker);
};
workerType workers[2][2] {
{
makeWorker(false, false, (asymmetricVertex*)nullptr),
makeWorker(false, true, (symmetricVertex*)nullptr)
},
{
makeWorker(true, false, (compressedAsymmetricVertex*)nullptr),
makeWorker(true, true, (compressedSymmetricVertex*)nullptr)
}
};
workers[compressed][symmetric](P, iFile, binary, mmap);
}
关于c++ - 没有多态性的非默认可构造类的运行时类型解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51824351/