Как уже говорилось, есть несколько вещей, о которых следует помнить, главным образом, убедитесь, что существует только одно определение функции.
Мне не очень нравится это решение, но вот оно.
Один заголовок, чтобы исключить их всех (pair.h)
#ifndef TEMPLATE_PAIR
#define TEMPLATE_PAIR
#include <stdlib.h>
#define PAIR_NAME(T1, T2) T1##T2##NAME
#define PAIR_PTR_NAME(T1, T2) T1##T2##PTR_NAME
#define PAIR_CREATE(T1, T2) MAKE##T1##T2
#define PAIR_PTR_CREATE(T1, T2) MAKE_PTR##T1##T2
#define PAIR_PTR_FREE(T1, T2) FREE##T1##T2
#define PAIR_DEFINITION(T1, T2) \
typedef struct { \
T1 first; \
T2 second ; \
} PAIR_NAME(T1, T2)
#define PAIR_PTR_DEFINITION(T1, T2) \
typedef struct { \
T1* first; \
T2* second ; \
} PAIR_PTR_NAME(T1, T2)
#define MAKE_PAIR_DECLARE(T1, T2) PAIR_NAME(T1, T2) PAIR_CREATE(T1, T2) (const T1& V1, const T2& V2)
#define MAKE_PAIR_PTR_DECLARE(T1, T2) PAIR_PTR_NAME(T1, T2) PAIR_PTR_CREATE(T1, T2) (const T1& V1, const T2& V2)
#define PAIR_PTR_FREE_DECLARE(T1, T2) void PAIR_PTR_FREE(T1, T2) (PAIR_PTR_NAME(T1, T2) & Pair)
#define MAKE_PAIR_SIGNATURE(T1, T2) PAIR_NAME(T1, T2) PAIR_CREATE(T1, T2) (const T1& V1, const T2& V2)
#define MAKE_PAIR_PTR_SIGNATURE(T1, T2) PAIR_PTR_NAME(T1, T2) PAIR_PTR_CREATE(T1, T2) (const T1& V1, const T2& V2)
#define FREE_PAIR_PTR_SIGNATURE(T1, T2) void PAIR_PTR_FREE(T1, T2) (PAIR_PTR_NAME(T1, T2) & Pair)
#define MAKE_PAIR_DEFINE(T1, T2) \
MAKE_PAIR_SIGNATURE(T1, T2) { \
PAIR_NAME(T1, T2) pair; \
pair.first = V1; \
pair.second = V2; \
return pair; \
}
#define MAKE_PAIR_PTR_DEFINE(T1, T2) \
MAKE_PAIR_PTR_SIGNATURE(T1, T2) { \
PAIR_PTR_NAME(T1, T2) pair; \
pair.first = malloc(sizeof(T1)); \
if (pair.first != 0) *(pair.first) = V1; \
pair.second = malloc(sizeof(T2)) ; \
if (pair.second != 0) *(pair.second) = V2; \
return pair; \
}
#define PAIR_PTR_FREE_DEFINE(T1, T2) \
FREE_PAIR_PTR_SIGNATURE(T1, T2) { \
free(Pair.first); \
free(Pair.second); \
}
#endif
Один заголовок, чтобы привести их все (defs.h):
#ifndef DEFS_HEADER
#define DEFS_HEADER
#include "pair.h"
typedef int* pInt;
PAIR_DEFINITION(int, int);
PAIR_DEFINITION(int, double);
PAIR_DEFINITION(double, double);
PAIR_DEFINITION(pInt, pInt);
PAIR_DEFINITION(float, int);
PAIR_PTR_DEFINITION(int, int);
MAKE_PAIR_DECLARE(int, int);
MAKE_PAIR_DECLARE(int, double);
MAKE_PAIR_DECLARE(double, double);
MAKE_PAIR_DECLARE(pInt, pInt);
MAKE_PAIR_DECLARE(float, int);
MAKE_PAIR_PTR_DECLARE(int, int);
PAIR_PTR_FREE_DECLARE(int, int);
#endif
И в темноте связывают их (осущ. в):
#include "defs.h"
MAKE_PAIR_DEFINE(int, int);
MAKE_PAIR_DEFINE(int, double);
MAKE_PAIR_DEFINE(double, double);
MAKE_PAIR_DEFINE(pInt, pInt);
// manual "instantiation"
MAKE_PAIR_SIGNATURE(float, int)
{
PAIR_NAME(float, int) local;
local.first = V1;
local.second = V2;
return local;
}
MAKE_PAIR_PTR_DEFINE(int, int);
PAIR_PTR_FREE_DEFINE(int, int);
В земле главной где тени лежат:
#include "defs.h"
int main(void)
{
PAIR_NAME(int, int) myPairInts;
PAIR_NAME(double, double) myPairDoubles;
PAIR_NAME(pInt, pInt) myPairPointers;
PAIR_NAME(float, int) myPairOther;
PAIR_PTR_NAME(int, int) pairPtr;
myPairInts = PAIR_CREATE(int, int) (1, 2);
myPairDoubles = PAIR_CREATE(double, double) (5, 6.5);
myPairPointers = PAIR_CREATE(pInt, pInt) (0, 0);
myPairOther = PAIR_CREATE(float, int) (1, 1);
pairPtr = PAIR_PTR_CREATE(int, int) (1, 2);
PAIR_PTR_FREE(int, int) (pairPtr);
return 0;
}
PAIR_NAME
создает структуру, содержащую значения, PAIR_PTR_NAME
содержит указатели на значения. PAIR_CREATE
и PAIR_PTR_CREATE
создают значения и заполняют данные внутри пары.
Вам нужно будет определить все необходимые комбинации в «impl.c». Любой блок компиляции может #include "defs.h"
и использовать пары.
EDIT - Ответы на вопросы:
- «Не будет ли это причиной проблемы, когда я использую этот раз в библиотеке или что-то в этом роде, а затем снова в программе, которая использует эту библиотеку как и пара «шаблон»?»
«pair.h» содержит только макросы, его можно безопасно использовать в любой библиотеке или программе.
Важно, чтобы вы не определяли одну и ту же функцию дважды. Я бы не стал определять одну и ту же структуру дважды.
Вы можете сделать следующее, хотя: - взять pair.h, defs.h и impl.c, как они выше и встраивать их в библиотеку (добавить любые необходимые __declspec(dllexport)
и __declspec(dllimport
) - вы можете затем #include pair.h
и defs.h
и используйте пары, определенные там в программе - если вы хотите использовать новые пары, скажем, для (float, float)
вам нужно будет добавить новый defs_my_program.h
и новый impl_my_program.c
, чтобы объявить и определить эти новые пары. Заголовок defs_my_program.h
может быть включен вместе с заголовком defs.h
, который предоставляет библиотека.
Вы по-прежнему получаете одно объявление и одно определение для каждой пары. Единственным недостатком является то, что вы не можете (безопасно) использовать пары «на лету», они должны быть централизованы.
- «, как вы выбрали имена типов и функций, чтобы быть действительно приносят некоторые проблемы с ним. Вы расстались пара с двумя значениями и один с двумя указателями. Кроме того, необходимо будет специализация для пары с одним указатель и одно значение, а для пары с одним значением и одним указателем.Таким образом, я бы уже имел 4 пары пар. Используя это для триплетов или даже более высоких кортежей, мне пришлось бы реализовать 2^n случаев ».
Ну, для начала, вы попросили std::pair
, а не для кортежа.
Обратите внимание, что std::pair
является эквивалентом PAIR_NAME
, нет std::pair
, который выделяет динамическую память.
Вам не нужны никакие новые специализации, если вам не нужно автоматически использовать malloc
. Пример с pInt
показывает, что вы можете создать s pair
из (int, int*)
или (int*, int)
. Просто значение указателя должно поступать из-за пределов pair
.
Если вы действительно хотите pair
из (int, int*)
, который автоматически выделяет память для int*
вам придется добавить его себе , если вы на самом деле нужно. Надеюсь, ты этого не сделаешь.
Для кортежей значений не очень оптимальным решением может быть использование pair
pair
и еще один элемент. Это даст вам структуру, содержащую три элемента. Что-то вроде этого, вероятно, можно сделать с помощью макромагнетики, сокращая этот экспоненциальный рост, о котором вы беспокоитесь.
Вы когда-нибудь слышали о '#ifndef #define' и включают gaurd: http://en.wikipedia.org/wiki/Include_guard? – 0x90
Почему бы просто не программировать на C++? – Sebivor
Ха, я видел такой метод в некоторых правильных проектах на С. Мех, почему бы и нет. Вы просто должны быть осторожны, чтобы правильно разобраться. Вам, вероятно, потребуется несколько файлов. –