【发布时间】:2012-11-23 08:07:46
【问题描述】:
为什么不能在模板函数中使用 NULL 作为默认指针参数? 让我们考虑以下代码:
template<class Graph, class NodeAttribs, class ArcAttribs> string
graphToGraphviz(Graph &graph,
NodeAttribs *nattribs = NULL,
ArcAttribs *aattribs = NULL,
string name = ""){
/*...*/
}
我希望能够这样称呼它:
graphToGraphviz(g);
我怀疑,编译器认为它无法解析 NULL 的类型,但如果属性为 NULL(存在 if 条件),则不会使用这些类型。但也许这种情况无法通过编译器以正确的方式解决。如果是,我该如何编写这样的重载函数,这将允许我使用短格式?
我有一个像这样重载它的想法:
class Empty{}
template<class Graph> string
graphToGraphViz(Graph &graph,
string name = ""){
return graphToGraphviz<Graph, Empty, Empty>(graph, NULL, NULL, name)
}
但是编译器给了我错误,除其他外,那个类 Empty 没有定义operator []。这又是不稳定的,但是我是否必须使所有这些“虚拟”运算符重载和空函数来满足编译器的要求,或者有更好的方法吗?
编辑: 请查看完整的源代码 - 它将 Lemon 图转换为 graphviz 格式: 我尝试使用 C++11 中的新语法(如下面的答案所示),但没有成功。
#ifndef GRAPHTOGRAPHVIZ_H_
#define GRAPHTOGRAPHVIZ_H_
#include <lemon/list_graph.h>
using namespace lemon;
using namespace std;
/* USAGE:
* ListDigraph::NodeMap<unordered_map<string, string>> nodeAttribs(g);
* ListDigraph::ArcMap<unordered_map<string, string>> arcAttribs(g);
* nodeAttribs[node]["label"] = "node_label";
* string dot = graphToGraphviz(g, &nodeAttribs, &arcAttribs, "hello");
*/
template<class Map>
string getAttribs(Map &map){
string attribs = "";
for (const auto &el : map){
if (el.second != "")
attribs += "\"" + el.first + "\"=\"" + el.second + "\",";
}
if (attribs != "")
attribs = " [" + attribs + "]";
return attribs;
}
template<class Graph, class NodeAttribs, class ArcAttribs> string
graphToGraphviz(Graph &graph,
NodeAttribs *nattribs = NULL,
ArcAttribs *aattribs = NULL,
string name = ""){
typedef typename Graph::template NodeMap<string> NodeMap;
typedef typename Graph::NodeIt NodeIterator;
typedef typename Graph::ArcIt ArcIterator;
NodeMap labels(graph);
ostringstream layout;
layout << "strict digraph \""+name+"\" {\n";
// prepare labels
for (NodeIterator node(graph); node != INVALID; ++node){
string label = "";
if (*nattribs != NULL)
label = (*nattribs)[node]["label"];
if (label == "") label = static_cast<ostringstream*>( &(ostringstream() << graph.id(node)) )->str();
label = "\"" + label + "\"";
labels[node] = label;
}
// initialize nodes
for (NodeIterator node(graph); node != INVALID; ++node){
layout << labels[node];
if (*nattribs != NULL)
layout << getAttribs((*nattribs)[node]);
layout << ";" << std::endl;
}
// initialize arcs
for (ArcIterator arc(graph); arc != INVALID; ++arc){
layout << labels[graph.source(arc)] << "->" << labels[graph.target(arc)];
if (*aattribs != NULL)
layout << getAttribs((*aattribs)[arc]);
layout << ";" << std::endl;
}
layout << "}";
return layout.str();
}
#endif /* GRAPHTOGRAPHVIZ_H_ */
使用 C++11 语法,函数头将如下所示:
template<class Graph, class NodeAttribs=ListDigraph::NodeMap<string>, class ArcAttribs=ListDigraph::NodeMap<string> > string
graphToGraphviz(Graph &graph,
NodeAttribs *nattribs = NULL,
ArcAttribs *aattribs = NULL,
string name = "")
但它不能编译并给出大量奇怪的错误。
【问题讨论】:
-
您对
Empty类的想法可能是最简单的。您也可以使用部分特化,但这可能会过大,具体取决于代码的复杂性。 -
@rodrigo:你不能部分特化一个函数。
-
@n.m.:哦,对了!但是,您可以使用某种
traits类并部分专门化这些...
标签: c++ templates c++11 overloading default