0

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.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Avishek Dutta
  • 97
  • 2
  • 11
  • 1
    It would help us if you could post the errors. Make sure you guard your `.h` file against multiple inclusions, see [here](http://stackoverflow.com/questions/1143936/pragma-once-vs-include-guards) or [here](http://stackoverflow.com/questions/787533/is-pragma-once-a-safe-include-guard). – Jens May 27 '14 at 15:25
  • 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 – Avishek Dutta May 27 '14 at 15:49
  • The LISTELEMENT is not known. Even if I define it as "node" inside ListFunctions.cpp the "double_node_list" is still an undeclared identifier. I have included ListFunctions.h twice once in my module and once in ListFunctions.cpp – Avishek Dutta May 27 '14 at 15:53

2 Answers2

9

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.

  • Well, I have single ended and double ended lists. In C I have defined append, prepend, remove etc on both these lists using the macros. – Avishek Dutta May 27 '14 at 16:18
  • While those macros are possibly okay (if a bit weird) in C, they are absolutely not an appropriate solution to the problem in C++. Learn the language fully before you continue. –  May 27 '14 at 18:31
  • *"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."* I know what you are saying, but the language *was* designed for the incremental improvement of C codebases to C++. While no person should *start* a new project in C++ with a "C with stuff mindset", updating existing code bit by bit and bringing "stuff" in is usage as-intended. (Anyone doing so should write some real C++ code first to have some clue about building toward a proper ultimate endpoint.) – HostileFork says dont trust SE Nov 19 '15 at 12:56
2

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.

Community
  • 1
  • 1
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158