I recently built a CSV library in pure C. The header file looks as follows:
#ifndef CSV_H
#define CSV_H
#include "unicode/ustdio.h"
#include "unicode/uchar.h"
#include "unicode/ucsdet.h"
#include "unicode/ustring.h"
#define T CSV_T
typedef struct T *T;
extern T CSV_new(char *filename);
extern void CSV_free(T *csv);
extern int CSV_length(T csv);
extern void CSV_print_info(T csv);
extern UChar **CSV_get_header(T csv);
extern UChar ***CSV_get_values(T csv);
extern long CSV_get_num_columns(T csv);
extern long CSV_get_num_lines(T csv);
extern char *CSV_get_charset(T csv);
#undef T
#endif
The actual definition of the struct CSV_T is done in the code file, to hide the implementation. I used the library quite often in different projects using pure C, no problem. Now I wanted to re-use the code in a GUI application that is built with C++, and I get the following error message:
Error C2373 'CSV_T': redefinition; different type modifiers ... xxx\Projects\LibCSV\LibCSV\csv.h 10
Does C++ handle something about typedefs different than C? Confusing somehow,...
Here's what your MCVE should look like:
typedef struct T *T;
This is a complete, one-line source file that reproduces the issue and has no dependencies. No macros, no headers, no unnecessary code.
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:1:19: error: conflicting declaration 'typedef struct T* T'
typedef struct T *T;
^
main.cpp:1:16: note: previous declaration as 'struct T'
typedef struct T *T;
^
The reason it works in C is that T
was not already the name of a struct; you needed the struct
prefix.
In C++, this is not true, because the struct
prefix wasn't required in the first place. As soon as you have declared that T
is a class (which, confusingly, you did in the typedef
itself!), you can't just give some other type (the one you're trying to create with the typedef
) the same name.
It's rather bizarre what you're doing anyway, making CSV_T
mean struct CSV_T*
. I suggest simply not doing this.
If you were simply sticking with a typedef struct CSV_T CSV_T
then this would work in both languages, but trying to make a different type with the same name just isn't going to work.