2


我正在尝试从 C 中的 C++ 标准库中重新创建一些类。例如,std::pair 类。
为了模拟模板,我当然使用了宏。这是它的外观示例:

#define _TEMPLATE_PAIR_STRUCT(T1, T2, TNAME, STRNAME) \
typedef struct {                                  \
    T1* first;                                    \
    T2* second;                                   \
} STRNAME;

#define _TEMPLATE_PAIR_NEW(T1, T2, TNAME, STRNAME) \
    STRNAME* TNAME##_new()                         \
    {                                              \
        STRNAME *new = malloc(sizeof( STRNAME ));  \
        new->first = malloc(sizeof(T1));           \
        new->second = malloc(sizeof(T2));          \
        return new;                                \
    }

如果我试图在多个源文件中使用这种结构,我必须多次生成代码。显然,这会导致错误。

有没有办法解决这个问题,所以我可以在 C 中使用这些“模板”?

4

3 回答 3

5

正如其他人所说,有几件事要记住,主要是确保只有一个函数定义。

我不是特别喜欢这个解决方案,但就是这样。

一个标题来统治它们(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

并在黑暗中束缚他们(impl.c):

#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_CREATEPAIR_PTR_CREATE创建值并填充对内的数据。

您需要在“impl.c”中定义所有必要的组合。任何编译单元都可以#include "defs.h"使用这些对。

编辑 - 问题的答案:

  1. “当我在库或类似的东西中使用它一次,然后在同时使用该库和“模板”对的程序中使用它时,这不会造成麻烦吗?”

“pair.h”只包含宏,它可以安全地用于任何库或程序中。

重要的是您不要两次定义相同的函数。我也不会两次定义相同的结构。

不过,您可以执行以下操作: - 将上面的 pair.h、defs.h 和 impl.c 构建到库中(添加任何必要的__declspec(dllexport)and __declspec(dllimport) - 然后您可以#include pair.hdefs.h程序中使用定义的对- 如果你想使用新的对,比如说(float, float)你需要添加一个新的defs_my_program.h和一个新impl_my_program.c的来声明和定义这些新的对。标defs_my_program.h头可以与defs.h库提供的标头一起包含。

您仍然会为每一对获得一个声明和一个定义。唯一的“缺点”是您不能真正(安全地)即时使用对,它们需要集中化。

  1. “您选择类型和函数名称的方式确实带来了一些问题。您将一对具有两个值和一个具有两个指针。您还需要对具有一个指针和一个值的一对进行专门化,并且对于具有一个值和一个指针的一对。所以我已经有 4 个对的情况。将它用于三元组甚至更高的元组,我将不得不实现 2^n 个情况。

好吧,对于初学者来说,你要求std::pair而不是touple。

请注意,std::pair它相当于PAIR_NAME,没有std::pair分配动态内存。

如果您不需要自动使用malloc. 带有的示例pInt表明您可以创建 s或。只是指针的需要来自外部。pair(int, int*)(int*, int)pair

如果你真的想要一个自动为你分配内存的pair你必须自己添加它,如果你真的需要它。我希望你不会。(int, int*)int*

对于值的元组,一个不太理想的解决方案可能是使用pairapair和另一个元素。这将为您提供一个包含三个元素的结构。类似的事情可能可以通过宏观魔法来完成,减少你担心的指数增长。

于 2013-05-18T22:00:06.217 回答
2

多次声明结构不是问题。

多次定义函数是一个问题。如果您将函数设为静态,那么它将成为每个文件一次的问题。即使在 C++ 中,有时人们也会显式地实例化模板。您可以拥有一个包含所有新功能的文件。

如果您想要一个自动解决方案,那么您需要查看 C++ 编译器如何实例化模板。这是很久以前使用的一种方法。

  • 在不使用 PAIR_NEW 的情况下编译和链接您的代码
  • 您将获得未定义的 _new() 函数。
  • 运行一个脚本,该脚本使用正确的 PAIR_NEW() 宏调用生成一个 C 文件,以定义未定义的符号
  • 编译这个新文件并重新链接您的项目,包括新文件。
于 2013-05-18T21:12:40.847 回答
1

如果这是一个好主意,则从问题中抽象出来,您的实现中有几处错误。

  • 永远不要隐藏;宏内部,这完全违背了使用它的地方的视觉预期。
  • 除了在 C++ 中,不接收参数的函数应该void().
  • 以下划线和大写字母开头的名称在所有上下文中为 C 实现保留。选择更好的命名约定。
  • 除了在 C++ 中,您的new函数不会初始化数据,这也是一个糟糕的命名约定。
  • 您将标识符new用作局部变量,如果有一天您想将其与某些 C++ 接口,那就不好了
  • 您的函数宏应分为三部分:(1)用于将函数名称组合在一起的命名约定,(2)inline定义和(3)外部“实例”,可让您准确生成函数符号一个编译单元。
于 2013-05-18T21:16:49.753 回答