Substitution from C to C++

This is a discussion on Substitution from C to C++ within the C++ Programming forums, part of the General Programming Boards category; Hello all, I'm using a library in C for my project. This library defines two functions for everything it does, ...

  1. #1
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50

    Substitution from C to C++

    Hello all,

    I'm using a library in C for my project. This library defines two functions for everything it does, one for int and other for long int. To use the long version, you must define USINGLONG. Then, inside the library, the author defined a macro

    Code:
    #ifdef USINGLONG
    #define FUNCTION(name) function_long_ ## name
    #else
    #define FUNCTION(name) function_int_ ## name
    #endif
    because the codes are the same. I have to do this too, but I would like to know if there is a C++ way of doing it.

    Thank you

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,633
    Quote Originally Posted by nepper271
    because the codes are the same.
    As in the implementation of the two functions are identical, save for the difference in type? If so, you could define a function template, or simply overload. To use the appropriate version, you simply pass an argument of the appropriate type.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    Yes, the implementation is the same very much like a template, changing only the type. The problem with using template is that I can't figure out how to change the function name in the call. E.g.:

    Code:
    void MyClass::MyExample () {
      SomeType a, b;
      FUNCTION (start) ();
      FUNCTION (create) (&a);
      FUNCTION (create) (&b);
      FUNCTION (something) (&a, &b, this->c);
      FUNCTION (destroy) (&a);
      FUNCTION (destroy) (&b);
    }
    I can see ways of doing it either repeting code with overload, or with templates using ifs for the types. However, I'm talking about dozens of functions, so that's something undesirable.

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,699
    The problem is that you have to compile the C library with either one definition or another; both can't be available to your template at once. Anyway, that shouldn't effect how you call the functions (as per your example). You could simply write:

    Code:
    void MyClass::MyExample () {
      SomeType a, b;
      start();
      create(&a);
      create(&b);
      something(&a, &b, this->c);
      destroy(&a);
      destroy(&b);
    }
    If you're capturing the return value, just be sure to define an integer type compatible with the C library, ie:

    Code:
    #ifdef USINGLONG
    #define MY_INT_TYPE long int
    #else
    #define MY_INT_TYPE int
    #endif
    Code:
    bool fun(bool value)
    {
        return std::pow(std::exp(1), std::complex<float>(0, 1) 
        * std::complex<float>(std::atan(1)*(1 << (value + 2))))
        .real() > 0;
    }

  5. #5
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    Actually, the C library is compiled with both definitions, and each with a different name. The functions in the C library are defined so that every difference from a long to a int is resolved with a #ifdef, including its definition of INT. Then the compiler makes the two versions

    Code:
    cc -o program_int.o program.c
    cc -o program_long.o program.c -DUSINGLONG
    Since they have different names, there is no conflict.

    I need to do the same thing, but I would like to know if there is a C++ way of doing it, that doesn't involve macros for the name selection and in which I don't have to write all function name twice.

    With templates I can do something like

    Code:
    //Obs.: I don't remember how to comparison between types, so suppose the following is valid
    
    if (TypeOf (T) == int) {
      function_int_start ();
      function_int_create (&a);
      //etc...
    } else if (TypeOf (T) == long int) {
      function_long_start ();
      function_long_create (&a);
      //etc...
    }
    With overloaded functions I can't do it, because most functions I make return and receive void.

  6. #6
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,543
    I still don't see why you need to know the type. Why not create a generic function_start<T>? You can put in a long, and you can return a long (which would be the type T).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    Like I said first : "I'm using a library in C for my project". It's not my library. function_int_start and function_long_start are already created. I need to use them.

  8. #8
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,543
    Ahh. Now it makes sense.
    If you don't want to rewrite your functions (and you probably don't), then all you need is to use C++'s static type system to automatically deduce the function to call:

    This will make sure only int and whatever other types you want are accepted:
    [code]template<typename T> void function_create(T& some_data) { static_assert(false, "Invalid type."); }
    template<> void function_create<int>(int& some_data) { function_int_create(&some_data); }
    Code:
    template<> void function_create<long>(long& some_data) { function_long_create(&some_data); }
    // ...
    This should also work, but types other than int and long may be implicitly converted to these types and ambiguity may result.
    Code:
    void function_create(long& some_data) { function_long_create(&some_data); }
    void function_create(int& some_data) { function_int_create(&some_data); }
    // ...
    Last edited by Elysia; 12-10-2010 at 09:08 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User nepper271's Avatar
    Join Date
    Jan 2008
    Location
    Brazil
    Posts
    50
    I'm not familiar with static_assert, so I went to make some tests. I tried this code:

    Code:
    #include <iostream>
    
    using namespace std;
    
    template < typename T > void function_create (T& a) {
      static_assert(false, "FAIL");
    }
    
    template <> void function_create (int &a) {
      cout << a << endl;
    }
    
    
    int main () {
      int a = 2;
    //  function_create<int> (a);
    }
    I figured from what you wrote, that this is an attempt to create the condition "If a not-defined T is instantiated, then FAIL". However this code already fails.

    Still, I'm supposed to write a case for a 'T = int' and a case for 'T = long int', isn't it?

  10. #10
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,543
    It's a c++0x feature. You'll need a c++0x compiler to compile it. Visual studio and gcc are two compilers that supports it.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,699
    Actually, the C library is compiled with both definitions, and each with a different name. The functions in the C library are defined so that every difference from a long to a int is resolved with a #ifdef, including its definition of INT. Then the compiler makes the two versions

    Code:
    cc -o program_int.o program.c
    cc -o program_long.o program.c -DUSINGLONG
    Since they have different names, there is no conflict.
    Okay, so now you have two object files with non-conflicting identifiers, but what about the header file - the identifiers in there are still dependant on whether or not USINGLONG is defined, right?

    I need to do the same thing, but I would like to know if there is a C++ way of doing it, that doesn't involve macros for the name selection and in which I don't have to write all function name twice.
    Well, assuming you've worked out the header file ambiguity described above, yes, there are a few C++ tricks you could use to achieve it. Here's one possibility:

    Code:
    void foo_int( void ){    }
    int bar_int( int ){    }
    
    void foo_long( void ){    }
    long int bar_long( long int ){    }
    
    template < typename Integer >
    struct table_of_function_pointers
    {    };
    
    /*
        This could probably be implemented as a macro...
    */
    template < >
    struct table_of_function_pointers< int >
    {
        table_of_function_pointers( void )
        : foo( foo_int ), bar( bar_int )
        {    }
    
        void ( *foo )( void );
        int ( *bar ) ( int );
    };
    
    template < >
    struct table_of_function_pointers< long int >
    {
        table_of_function_pointers( void )
        : foo( foo_long ), bar( bar_long )
        {    }
    
        void ( *foo )( void );
        long ( *bar ) ( long );
    };
    
    template < typename Integer >
    struct baz
    {
        baz( void )
        {
            tab.foo( );
            Integer val = tab.bar( Integer( 1024 ) );
        }
        
        static table_of_function_pointers< Integer > tab;
    };
    
    template < typename Integer >
    table_of_function_pointers< Integer > baz< Integer >::tab 
        = table_of_function_pointers< Integer >( );
    
    int main( void )
    {
        baz< int > qux; // okay
        baz< long int > fop; // okay
        baz< double > sol; // error
    }
    Not too bad, I guess...but then again, good old fashioned "copy and paste" code reuse probably wouldn't be much worse either!
    Last edited by Sebastiani; 12-10-2010 at 10:39 AM. Reason: formatting, grammar
    Code:
    bool fun(bool value)
    {
        return std::pow(std::exp(1), std::complex<float>(0, 1) 
        * std::complex<float>(std::atan(1)*(1 << (value + 2))))
        .real() > 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. macro substitution rule
    By Shivanand in forum C Programming
    Replies: 2
    Last Post: 10-09-2010, 09:03 AM
  2. Substitution Cipher Program Problem...
    By kalor_alros in forum C++ Programming
    Replies: 1
    Last Post: 09-01-2009, 11:06 AM
  3. Liskov substitution principle
    By George2 in forum C++ Programming
    Replies: 9
    Last Post: 02-25-2008, 04:30 AM
  4. Backward substitution in gaussian elimination
    By Meander14 in forum C Programming
    Replies: 0
    Last Post: 09-30-2007, 07:02 AM
  5. Substitution Cipher Program Problem...
    By Junior89 in forum C++ Programming
    Replies: 13
    Last Post: 12-28-2005, 04:02 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21