Null как аргумент шаблона по умолчанию

Почему нельзя использовать 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      = "")

но он не компилируется и дает массу странных ошибок.

2

Решение

Если вы используете C ++ 11, вы можете сделать это:

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

Я не нашел соответствующего языка в стандарте, но gcc принимает его.

1

Другие решения

Компилятор имеет проблему при вызове:

graphToGraphviz(g);

Теперь, какой тип NodeAttribs а также ArcAttribs ?
Компилятор должен определить его тип независимо от того, используете вы его или нет. Потому что использование или не использование — это проверка во время выполнения.
С вашим текущим кодом вышеупомянутые типы становятся без выводима.

как я мог написать такое перегруженный функция

На ваш вопрос есть ответ !!
перегрузка template функция, удалите аргументы по умолчанию из вашего оригинал Функция шаблона и пусть обе функции сосуществуют:

template<class Graph>
string graphToGraphviz(Graph &graph, string name = "");
2

Ты пытался

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 действительные (конкретные) классы, которые можно использовать в этом слоте?

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector