Using #define for changing the class name

I am currently implementing my own version of a foward list and I wanted to be able to change between my class and STL's easily while compiling it. I've tried this method before and it worked... not sure if it was pure luck. Anyways, It isn't working now. Is there a better way for doing this?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "Header.h"

//selecting foward list
#ifdef MY_FOWARD_LIST

#include "Forward_List.h"
#define FWRDLIST Forward_list //name of the class that I've made

#else
#include <forward_list>
#define FWRDLIST std::forward_list

#endif // MY_FOWARD_LIST end


void CheckList(FWRDLIST<int> f_list){
  // Testando iterators
  std::cout << "\nSize: " << f_list.size() << std::endl;
  
  if(f_list.empty()) std::cout << "Empty!\n";
  else{
    for(FWRDLIST<int>::iterator lit = f_list.begin(); lit != f_list.end(); lit ++){
      std::cout << "Elements of the list: " << *lit << std::endl;
    }
  }
  
}

int main(){
  
  std::cout <<">> Program start.\nBUILDING LIST...\n"
  FWRDLIST<int> forward_list;
  
  CheckList(forward_list);
}


I get the following error:
src/Drive_Foward_List.cpp: In function ‘int main()’:
src/Drive_Foward_List.cpp:7:18: error: expected ‘;’ before ‘Forward_list’
 #define FWRDLIST Forward_list
src/Drive_Foward_List.cpp:31:3: note: in expansion of macro ‘FWRDLIST’
   FWRDLIST<int> forward_list;
   ^
src/Drive_Foward_List.cpp:33:13: error: ‘forward_list’ was not declared in this scope
   CheckList(forward_list);



Here is the version that worked.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

#ifdef M1
#define CLASS m1
#else
#define CLASS m2
#endif


class m1{
    public:
    m1(){}
    
    int get() { return 1; }
};

class m2{
    public:
    m2(){}
    
    int get() { return 2; }
};

int main(){
    CLASS a;
    std::cout << a.get() << std::endl;
    return EXIT_SUCCESS;
}
Last edited on
> expected ‘;’ before ‘Forward_list’

Missing semicolon at the end of line 31.

Note: std::forward_list<> does not have the member 'size()'

Consider:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <forward_list>
#include <type_traits>

template < typename T > struct my_forward_list { /* ... */ } ;

constexpr bool USE_MY_FORWARD_LIST = false ; // true or false as required

template < typename T > using forward_list = typename std::conditional< USE_MY_FORWARD_LIST,
                                                                        my_forward_list<T>,
                                                                        std::forward_list<T> >::type ;

int main() {

    forward_list<int> flist ; // my_forward_list if USE_MY_FORWARD_LIST is true,
                              // std::forward_list otherwise
}
Last edited on
Thank you very much.

Edit:
About using a constexpr: my assignment says that the user has to select wich list he would like to use through the command line at the terminal. So I guess it would be better to use a #define the way I have been using since I just need to -DUSE_MY_CLASS while at it... ? For what I've read, a constexpr variable does pretty much what a #define variable should be doing for my situation. Again, thank you very much.
Last edited on
> So I guess it would be better to use a #define the way I have been using
> since I just need to -DUSE_MY_CLASS while at it... ?
> For what I've read, a constexpr variable does pretty much what a #define variable should be doing for my situation.

A construct supported by the C++ type system and other language rules is inherently more robust and more flexible than a pure pre-processor technique.

For instance, if my_forward_list_for_trivial_types<T> is specially written for trivial types:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <forward_list>
#include <type_traits>
#include <string>
#include <iostream>

template < typename T > struct my_forward_list_for_trivial_types // specially written (and optimised) for trivial types
{ static_assert( std::is_trivial<T>::value, "forward_list for only trivial types" ) ; /* ... */ } ;

constexpr bool USE_MY_FORWARD_LIST =  
                                      #ifdef USE_CUSTOM_FORWARD_LIST
                                          true ;
                                      #else
                                          false ; 
                                      #endif // USE_CUSTOM_FORWARD_LIST


template < typename T >
using forward_list = typename std::conditional< USE_MY_FORWARD_LIST && std::is_trivial<T>::value,
                                                my_forward_list_for_trivial_types<T>, std::forward_list<T> >::type ;

int main() {

    forward_list<int> flist_int ; // my_forward_list_for_trivial_types<int> if USE_CUSTOM_FORWARD_LIST is defined
    forward_list<std::string> flist_str ; // always std::forward_list<std::string>

    #ifdef USE_CUSTOM_FORWARD_LIST
        std::cout << "using my_forward_list_for_trivial_types<int>\n" ;
        static_assert( std::is_same< decltype(flist_int), my_forward_list_for_trivial_types<int> >::value, "unexpected type" ) ;
    #else 
        std::cout << "using std::forward_list<int>\n" ;
        static_assert( std::is_same< decltype(flist_int), std::forward_list<int> >::value, "unexpected type" ) ;
    #endif

    std::cout << "using std::forward_list<std::string>\n---------------\n" ;
    static_assert( std::is_same< decltype(flist_str), std::forward_list<std::string> >::value, "unexpected type" ) ;
}

http://coliru.stacked-crooked.com/a/cc8feb7cccecd95e
> A construct supported by the C++ type system and other language rules is inherently more robust and more flexible than a pure pre-processor technique.

I'll keep this on mind for my future assignments . I'm using constexp a lot more now. Thanks for helping me out!
Last edited on
Topic archived. No new replies allowed.