【问题标题】:Templates in C using void * in C++在 C++ 中使用 void * 的 C 模板
【发布时间】:2014-08-10 15:53:29
【问题描述】:

我有一个用 C++ 编写的泛型类,作为练习,我一直在尝试将其移植到 C。我尝试将 typedef 用于特定类型,但意识到这可能是错误的做法。我正在尝试使用 void 指针,但是我意识到我无法实例化泛型类是我缺少的东西吗?

ctrie.h

#ifndef _COM_WORDGAME_UTILITY_TRIE_H_KYLE
#define _COM_WORDGAME_UTILITY_TRIE_H_KYLE
#ifdef __cplusplus
extern "C"{ //this is used to identify following code as C specific code which will enforce C style name mangling
#endif


typedef struct Trie Trie;

//Create new Trie Object
Trie* newTrie(void * defVal);
//return number of key-value pairs
int size(Trie * t);
//return default value set by user
void * getDefaultValue(Trie * t);
//Check if returned value is not equal to default value
bool contains(Trie * t,const char * key);
//Return Value
void * get(Trie * t,char * key);
//Insert String into symbol Table
void put(Trie * t,char * s,void * val);
//Find and return longest prefix of s in TST
char * longestPrefix(Trie * t,char * s);
//compress the table making it immutable returning the number of nodes removed
int compress(Trie * t);

#ifdef __cplusplus
#include "cTrie.cpp"//quick hack to add cTrie without linking
}
#endif
#endif

ctrie.cpp

#include "Trie.hpp" //C++ code
#include "Trie.h" //C code

extern "C"{
using namespace com::wordgame::utility::trie;

//Create new Trie Object
Trie* newTrie(void * defVal){
    return new Trie<typeid(defVal)>(defVal);    
};
//return number of key-value pairs
int size(Trie * t){}
//return default value set by user
void * getDefaultValue(Trie * t){}
//Check if returned value is not equal to default value
bool contains(Trie * t,const char * key){}
//Return Value
void * get(Trie * t,char * key){}
//Insert String into symbol Table
void put(Trie * t,char * s,void * val){}
//Find and return longest prefix of s in TST
char * longestPrefix(Trie * t,char * s){}
//compress the table making it immutable returning the number of nodes removed
int compress(Trie * t){}


}

【问题讨论】:

  • TL;DR; 您可以在 c 中尝试的所有方法都是根据约定的假设进行转换!我非常怀疑您是否可以使用 c 重现类似的东西,例如 c++ 模板,但是使用笨拙且可能容易出错的宏实现!
  • 包含双下划线或以下划线开头后跟大写字母的名称保留到实现(即编译器)以供任何使用。使用像 _COM_WORDGAME_UTILITY_TRIE_H_KYLE 这样的名字是个坏主意。

标签: c++ c templates generics void-pointers


【解决方案1】:

C++ 中模板化容器类型的主要优势之一是能够提供一种很好的语法方式将相关对象嵌入到结构本身中,例如典型的std::vector&lt;T&gt;(通常实现为简单数组) 可以具有T步幅。要在 C 中完成类似的事情,您需要将整个函数实现为一堆宏,然后“实例化”为每种类型设置的函数,例如,C 中的简单“向量”实现可能看起来像这样(这取决于你问的是谁,是丑陋的、美丽的还是邪恶的)

#define VECTORFUNCS(T) \
  typedef struct { \
    T* arr; \
    size_t narr; \
    size_t capacity; \
  } VECTOROF_##T; \
  \
  void vector_##T##_reserve(VECTOROF_##T *v, size_t n) { \
    // \
  } \
  const T* vector_##T##_at(VECTOROF_##T *v, size_t ix) { \
    return v->arr[ix]; \
  } \

VECTORFUNCS(int)
VECTORFUNCS(struct sockaddr)

// 等等

作为旁注,这也可以通过简单地传递sizeof(T) 并为任何实现使用一组函数来更“干净”地实现(取决于你问谁);这些函数需要将arr 元素视为char* 并正确确定各种操作的偏移量)。

但是,如果您的模板类所做的只是为类型安全附加一个指向 T 的指针,则您可以完全在 C 中执行此操作而没有太多麻烦,当然您不会“实例化”每个模板时间(也不是必需的。C 使从 void 进行的转换变得不那么烦人了)。

【讨论】:

  • 有趣的是,您的示例不适用于struct sockaddr(创建VECTOROF_struct sockadrr,这不是一个有效的结构名称。嗯,它清楚地表明了这个C 宏抽象是多么容易出错。
  • 是的,我什至没有想过这个:)
猜你喜欢
  • 2012-11-02
  • 2021-07-08
  • 1970-01-01
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 1970-01-01
  • 2018-07-08
相关资源
最近更新 更多