Как заменить шаблон ‹typename на макрос?

Каким макросом я могу заменить шаблон "шаблон..." на что-то более короткое? то есть: вместо этого:

template <typename NodeDataT, typename ArcDataT>
/*constructor*/ GraphDirected::
GraphDirected()
{
}
template <typename NodeDataT, typename ArcDataT>
/*destructor*/ GraphDirected::
~GraphDirected()
{
    clear();
}    
template <typename NodeDataT, typename ArcDataT>
void GraphDirected::
clear()
{
    nodes.clear();
    arcs.clear();
}

Я хочу написать это:

boilerplate(/*constructor*/)
GraphDirected()
{
}
boilerplate(/*destructor*/)
~GraphDirected()
{
    clear();
}
boilerplate(void)
clear()
{
    nodes.clear();
    arcs.clear();
}

И, конечно же, в конце мне понадобится какая-то защита (? #undef?), чтобы другие файлы не испортились.

Если это не намного сложнее, как можно справиться с такими уродствами?:

template <typename ElemType>
typename BST<ElemType>::nodeT * BST<ElemType>::
recFindNode(nodeT *t, ElemType & key) { ... }

person user1358    schedule 08.01.2013    source источник
comment
Сначала я боялся, что кому-то нужен макрос только для трех токенов template <typename.   -  person aschepler    schedule 08.01.2013
comment
Почему бы не определить эти методы прямо в определении класса?   -  person ipc    schedule 08.01.2013
comment
@ipc: Точно моя мысль!   -  person Nawaz    schedule 08.01.2013
comment
@ipc: все они будут встроены   -  person user1358    schedule 08.01.2013
comment
это просто примеры методов   -  person user1358    schedule 08.01.2013
comment
функции шаблона всегда являются встроенными.   -  person ipc    schedule 08.01.2013
comment
@ipc: не совсем так, типы заменяются, а затем компилируются, что не то же самое, что встраивание (кстати: рекурсивные функции не могут быть встроены, так как вы не знаете глубину рекурсии во время компиляции)   -  person user1358    schedule 08.01.2013
comment
@ipc: см. stackoverflow.com/a/5431498/185819.   -  person Dark Falcon    schedule 08.01.2013
comment
@DarkFalcon: Это именно то, что я сказал.   -  person ipc    schedule 08.01.2013
comment
Какие у вас проблемы? Это должно быть выполнимо (хотя никто бы этого не рекомендовал) без каких-либо сложных заклинаний - это простая замена текста.   -  person molbdnilo    schedule 08.01.2013
comment
@ipc: Нет, это не так. Вы сказали, что они всегда встроены. Это не то, о чем говорится в этом посте. Встраивание и шаблоны не связаны напрямую.   -  person Dark Falcon    schedule 08.01.2013
comment
Я сказал, что они всегда встроены (!= всегда встроены). На то, встроены они или нет, повлиять нельзя.   -  person ipc    schedule 08.01.2013
comment
@DarkFalcon: пусть он ошибается   -  person user1358    schedule 08.01.2013


Ответы (4)


Я бы не советовал вам использовать MACRO только для того, чтобы избежать нескольких токенов. Поскольку определение элементов шаблона класса должно находиться в одном и том же файле, вы должны определить их в одном и том же файле, даже если вы делаете это вне класса.

Лучшим решением является определение членов внутри самого класса, чтобы вам не приходилось повторять маркеры каждый раз, когда вы определяете член.

Помните, что шаблоны генерируют уродливые сообщения об ошибках, а МАКРОС — это ЗЛО. Если вы объедините и то, и другое, вы увидите еще более уродливые и безумные сообщения об ошибках, когда что-то пойдет не так.

person Nawaz    schedule 08.01.2013

хорошо, я не вижу ничего плохого, если вы можете украсить свой шаблон шаблона:

#define pretty ugly

пока вы чувствуете, что это не вредит.

Для типов вы всегда можете сделать typedef

person Community    schedule 08.01.2013

Если вам действительно не нравится печатать, вы можете заменить typename на class, использовать стандартные имена шаблонов для своего домена приложения и написать struct вместо class, чтобы не печатать public:, и, наконец, сделать класс только заголовком:

template <class N, class A>
struct GraphDirected
{
    GraphDirected() {} // default constructor
    // rest of the class definition

private:
    // helpers and data go here
};
person TemplateRex    schedule 08.01.2013

Препроцессор C++ очень мало знает о коде, над которым он работает. Таким образом, вам потребуется #define термины, которые вы хотите использовать.

Однако что-то вроде:

template <typename NodeDataT, typename ArcDataT>
/*constructor*/ GraphDirected::
GraphDirected()
{
}
template <typename NodeDataT, typename ArcDataT>
/*destructor*/ GraphDirected::
~GraphDirected()
{
    clear();
}    
template <typename NodeDataT, typename ArcDataT>
void GraphDirected::
clear()
{
    nodes.clear();
    arcs.clear();
}

Может быть легко переписано с этим в каком-то заголовке:

#define boilerplate(rType) boilerplate_template rType boilerplate_class::

И затем в верхней части определения класса:

#define boilerplate_class GraphDirected
#define boilerplate_template template <typename NodeDataT, typename ArcDataT>

Итак, вы можете использовать:

boilerplate(/*constructor*/)
GraphDirected()
{
}
boilerplate(/*destructor*/)
~GraphDirected()
{
    clear();
}
boilerplate(void)
clear()
{
    nodes.clear();
    arcs.clear();
}

Примечание. Как уже отмечалось, это плохая идея. В таком простом случае, как пример, две #define в верхней части файла объяснят код всем, кто пытается его поддерживать. Однако имейте в виду, что это может быстро привести к нечитаемому и неподдерживаемому коду. Лучшее решение — использовать редактор, который может дополнить их за вас и свернуть так, чтобы вы их не видели. Таким образом, фактический файл остается в более стандартном формате для следующего редактирования (будь то вы или кто-то другой).

person unDeadHerbs    schedule 22.09.2017