Reputation: 99
I have a .inc file written in C. This contains some defines and method signatures with their implementations.
.inc file:
#define CONCAT(x,y) x ## y
#define LCONCAT(x,y) CONCAT(x,y)
#define DLIST LCONCAT(LCONCAT(double_,LISTELEMENT),_list)
#define DELETEDFIRST LCONCAT(delete_first_double_,LISTELEMENT)
int DELETEDFIRST (DLIST **first, DLIST **last);
int DELETEDFIRST (DLIST **first, DLIST **last)
{...}
I want to bring this to c++. In my .h file I have the define directives and the method signatures (encapsulated within a namespace). and in the .cpp I have only the method implementations.
.h file
#define CONCAT(x,y) x ## y
#define LCONCAT(x,y) CONCAT(x,y)
#define DLIST LCONCAT(LCONCAT(double_,LISTELEMENT),_list)
#define DELETEDFIRST LCONCAT(delete_first_double_,LISTELEMENT)
namespace ListFunctions {
int DELETEDFIRST (DLIST **first, DLIST **last);
}
.cpp file
# include ListFunctions.h
namespace ListFunctions {
int DELETEDFIRST (DLIST **first, DLIST **last) {...}
}
I plan to use these list functions in the development of my module. In my module.h I define a type double_node_list (double ended) and in my module.cpp I define LISTELEMENT as "node" and then include the ListFunctions.h. But the same include in ListFunctions.cpp leads to compilation errors:
..\ListFunctions.h(86): error C2065:'double_LISTELEMENT_list' : undeclared identifier
..\ListFunctions.h(86): error C2065: 'first' : undeclared identifier
..\ListFunctions.h(86): error C2065: 'double_LISTELEMENT_list' : undeclared identifier
..\ListFunctions.h(86): error C2065: 'last' : undeclared identifier
..\ListFunctions.h(86): error C2078: too many initializers
Later I want to translate the c style implementations to c++. As I lack experience I want to know if others agree with what I am doing.
Upvotes: 0
Views: 2966
Reputation: 66961
As to your specific problem, both the C and the C++ are invalid, and both should be invoking that error. The solution is to put this line before the functions, which tells the compiler that later on this structure will be defined, but right now we'll need pointers or references to it.
struct DLIST;
However, the major problem you're running into is that your goal appears to be to put the function definitions in a cpp file. Unfortunately, that can't be cleanly done in C nor C++ in a generic way. The problem is you want to be able to specialize the List for various types (via templates or macros), but when you compile that cpp file itself, there's no way for it to know what types to specialize the list for. For generic structures in C and C++, usually the definitions still must be in a header or include file of some sort.
There is one alternative, that would allow you to put the function definitions into a cpp file, but it's very wierd and I don't recommend it:
list_declarations.hpp
template<class LISTELEMENT>
class double_list {
typedef LISTELEMENT value_type;
struct iterator {
...iterator stuff
};
static int DELETEDFIRST (iterator first, iterator last);
};
extern template class double_list<int>; //declare int specialization
extern template class double_list<char>; //declare char specialization
list_definitions.cpp:
#include "list_declarations.h"
template<class LISTELEMENT>
int double_list<LISTELEMENT>::DELETEDFIRST(
double_list<LISTELEMENT>::iterator first,
double_list<LISTELEMENT>::iterator last)
{
...implementation
}
template class double_list<int>; //define int specialization
template class double_list<char>; //define char specialization
//note that all of these _must_ be in the same file as the function definitions
The normal way to make a generic list in C++ would be something vaguely like this:
#pragma once
template<class LISTELEMENT, class allocator=std::allocator<LISTELEMENT>>
class double_list {
public:
typedef allocator allocator_type;
typedef typename allocator::value_type value_type;
typedef typename allocator::reference reference;
typedef typename allocator::const_reference const_reference;
typedef typename allocator::difference_type difference_type;
typedef typename allocator::size_type size_type;
class iterator {
DLIST * current;
explicit iterator(DLIST* c);
public:
typedef LISTELEMENT value_type;
typedef LISTELEMENT& reference;
typedef LISTELEMENT* pointer;
typedef std::ptrdif_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator();
iterator& operator++(); //prefix increment
iterator operator++(int); //postfix increment
iterator& operator--(); //prefix decrement
iterator operator--(int); //postfix decrement
reference operator*() const;
pointer operator->() const;
friend bool operator==(const iterator&, const iterator&);
friend bool operator!=(const iterator&, const iterator&);
friend void swap(iterator& lhs, iterator& rhs);
};
class const_iterator {
const DLIST * current;
explicit iterator(const DLIST* c);
public:
const_iterator(iterator c);
...see above
};
double_list();
double_list(const double_list& rhs);
~double_list();
double_list& operator=(const double_list& rhs);
int delete_first(iterator first, iterator last);
private:
pointer first;
pointer last;
};
Plus any other members of interest in Writing your own STL Container. Since it's a template class, all the function definitions would have to be in the header. Obviously, this is remarkably different from the C way.
Upvotes: 2
Reputation:
Stop. It's evident that you know C, but you do not know C++. Learn C++ before you try to write code using it. It is a significantly different language from C, and trying to write C++ as if it were "C with stuff" will result in bad code.
First: What you want here is almost certainly a C++ class
with methods, not a namespace containing functions that operate on a data type (probably a structure?).
Second: I'm not sure what precisely all of the macros you've defined here are doing, but it almost looks as though you are trying to define a set of variant functions. This concept already exists in C++, as templates. Do not try to replicate it with macros; you'll just confuse anyone who reads your code.
Upvotes: 9