テンプレート化された関数内でデフォルトのポインタ引数として 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 []
定義されていないというエラーを私に与えます。これもまた不安定ですが、コンパイラを満足させるためにこれらすべての「ダミー」演算子のオーバーロードと空の関数を作成する必要がありますか、それともこれを行うためのより良い方法はありますか?
編集:完全なソースコードを見てください-レモングラフを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 = "")
しかし、それはコンパイルされず、大量の奇妙なエラーが発生します。