2

テンプレート化された関数内でデフォルトのポインタ引数として 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      = "")

しかし、それはコンパイルされず、大量の奇妙なエラーが発生します。

4

3 に答える 3

2

次の呼び出し時にコンパイラに問題があります。

graphToGraphviz(g);

NodeAttribsとの型は何ArcAttribsですか?
コンパイラは、使用しているかどうかに関係なく、その型を推測する必要があります。使用するか使用しないかはランタイム チェックであるためです。
現在のコードでは、上記の型は推論不能になります。

そのようなオーバーロードされた関数をどのように書くことができますか

あなたの質問には答えがあります!!
関数をオーバーロードし、元のtemplateテンプレート関数からデフォルトの引数を削除して、 両方の関数を共存させます。

template<class Graph>
string graphToGraphviz(Graph &graph, string name = "");
于 2012-11-23T08:15:04.737 に答える
1

C++11 を使用している場合は、次のようにすることができます。

template<class Graph, class NodeAttribs=Empty, class ArcAttribs=Empty> ...

標準で関連する言語を見つけられませんでしたが、gcc はそれを受け入れます。

于 2012-11-23T09:03:21.070 に答える
1

やってみました

template<class Graph, class NodeAttribs, class ArcAttribs> string
graphToGraphviz(Graph       &graph,
                NodeAttribs *nattribs = (<NodeAttribsClass>*)NULL,
                ArcAttribs  *aattribs = (<ArcAttribsClass>*)NULL,
                string      name      = ""){
   /*...*/
}

また

template<class Graph, class NodeAttribs = NodeAttribsClass, class ArcAttribs = ArcAttribsClass> string
graphToGraphviz(Graph       &graph,
                NodeAttribs *nattribs = NULL,
                ArcAttribs  *aattribs = NULL,
                string      name      = ""){
   /*...*/
}

そのスロットで使用できる有効な (具体的な) クラスはどこNodeAttribsClassにあり ますか?ArcAttribsClass

于 2012-11-23T08:13:57.670 に答える