Variadic function can have type safety.

Discussion in 'C++' started by Nephi Immortal, Dec 20, 2012.

  1. The compiler usually cannot check whether the unnamed arguments passed are of the type the function expects, or convert them to the required type. Therefore, care should be taken to ensure correctness in this regard, since undefined behavior results if the types do not match.

    For example, printf( “”, … ) is a variadic function. You can rewriteit in your own variadic function to implement type safety and type checking when possible. The class type is good choice unless you want type checking. Also, you can insert assertion if you want type safety.

    What happen if you use va_list? The va_list is truly char* type. If you put string into va_list, then va_list is invalid because of wrong type and does not have type checking.

    There are many ways I can overcome the limitation of variadic function. You can put unnamed class type into printf function as long as printf can have more than 8 overloading functions. When you read my code, it looks very reasonable readability.

    Take a look at my code below. I borrowed sample code from Microsoft library. I made some modifications and I added my class type. Please comment what do you think.

    // variable_argument_lists.cpp
    //#include <stdio.h>
    //#include <stdarg.h>

    #include<iostream>
    #include<string>
    #include<stack>
    #include <cassert>
    #include <tchar.h>

    using namespace std;

    class User_Type
    {
    public:
    enum Built_In_Types
    {
    eInt_Type,
    eFloat_Type,
    eChar_Type,
    eString_Type
    };

    protected:
    union Types
    {
    int i;
    float f;
    char c;
    char *s;
    } types;

    public:
    User_Type()
    {
    }

    ~User_Type()
    {
    }

    virtual Built_In_Types get_type() = 0;
    virtual Types get_value() = 0;
    };

    template< typename T >
    class Derived_User_Type : public User_Type
    {
    public:
    explicit Derived_User_Type( T data );
    ~Derived_User_Type();

    virtual Built_In_Types get_type();
    virtual Types get_value();
    };

    template<>
    class Derived_User_Type< int > : public User_Type
    {
    public:
    explicit Derived_User_Type( int data )
    {
    types.i = data;
    }

    ~Derived_User_Type()
    {
    }

    virtual Built_In_Types get_type()
    {
    return eInt_Type;
    }

    virtual Types get_value()
    {
    return types;
    }
    };

    template<>
    class Derived_User_Type< float > : public User_Type
    {
    public:
    explicit Derived_User_Type( float data )
    {
    types.f = data;
    }

    ~Derived_User_Type()
    {
    }

    virtual Built_In_Types get_type()
    {
    return eFloat_Type;
    }

    virtual Types get_value()
    {
    return types;
    }
    };

    template<>
    class Derived_User_Type< char > : public User_Type
    {
    public:
    explicit Derived_User_Type( char data )
    {
    types.c = data;
    }

    ~Derived_User_Type()
    {
    }

    virtual Built_In_Types get_type()
    {
    return eChar_Type;
    }

    virtual Types get_value()
    {
    return types;
    }
    };

    template<>
    class Derived_User_Type< char* > : public User_Type
    {
    public:
    explicit Derived_User_Type( char* data )
    {
    types.s = data;
    }

    ~Derived_User_Type()
    {
    }

    virtual Built_In_Types get_type()
    {
    return eString_Type;
    }

    virtual Types get_value()
    {
    return types;
    }
    };

    typedef Derived_User_Type< int > Int_Type;
    typedef Derived_User_Type< float > Float_Type;
    typedef Derived_User_Type< char > Char_Type;
    typedef Derived_User_Type< char* > String_Type;

    class Argument_List
    {
    public:
    Argument_List()
    {
    }

    ~Argument_List()
    {
    }

    User_Type& get_parameter()
    {
    return *list.top();
    }

    void push( User_Type& list )
    {
    this->list.push( &list );
    }

    void pop()
    {
    list.pop();
    }

    int get_size()
    {
    return list.size();
    }

    private:
    stack< User_Type* > list;
    };

    void vprint( string str, Argument_List& list );

    void print( string str, User_Type& arg1 )
    {
    Argument_List list;
    list.push( arg1 );
    vprint( str, list );
    }

    void print( string str, User_Type& arg1, User_Type& arg2 )
    {
    Argument_List list;
    list.push( arg2 );
    list.push( arg1 );
    vprint( str, list );
    }

    void print( string str, User_Type& arg1, User_Type& arg2, User_Type& arg3 )
    {
    Argument_List list;
    list.push( arg3 );
    list.push( arg2 );
    list.push( arg1 );
    vprint( str, list );
    }

    void print( string str, User_Type& arg1, User_Type& arg2, User_Type& arg3, User_Type& arg4 )
    {
    Argument_List list;
    list.push( arg4 );
    list.push( arg3 );
    list.push( arg2 );
    list.push( arg1 );
    vprint( str, list );
    }


    // ShowVar takes a format string of the form
    // "ifcs", where each character specifies the
    // type of the argument in that position.
    //
    // i = int
    // f = float
    // c = char
    // s = string (char *)
    //
    // Following the format specification is a variable
    // list of arguments. Each argument corresponds to
    // a format character in the format string to which
    // the szTypes parameter points

    //void ShowVar( char *szTypes, ... )
    void vprint( string szTypes, Argument_List& list )
    {
    // va_list vl;
    // int i;

    // szTypes is the last argument specified; you must access
    // all others using the variable-argument macros.
    // va_start( vl, szTypes );

    // Step through the list.
    string::iterator iter = szTypes.begin();

    // for( i = 0; szTypes != '\0'; ++i )
    for( ; iter != szTypes.end(); ++iter )
    {
    union Printable_t
    {
    int i;
    float f;
    char c;
    char *s;
    } Printable;

    // Type to expect.
    // switch( szTypes )
    switch( *iter )
    {
    case 'i':
    _ASSERT_EXPR( User_Type::eInt_Type == list.get_parameter().get_type(), _TEXT("This current type is NOT int type.") );
    // Printable.i = va_arg( vl, int );
    Printable.i = list.get_parameter().get_value().i;
    list.pop();
    // printf_s( "%i\n", Printable.i );
    cout << Printable.i << endl;
    break;

    case 'f':
    _ASSERT_EXPR( User_Type::eFloat_Type == list.get_parameter().get_type(), _TEXT("This current type is NOT float type.") );
    // Printable.f = va_arg( vl, double );
    Printable.f = list.get_parameter().get_value().f;
    list.pop();
    // printf_s( "%f\n", Printable.f );
    cout << Printable.f << endl;
    break;

    case 'c':
    _ASSERT_EXPR( User_Type::eChar_Type == list.get_parameter().get_type(), _TEXT("This current type is NOT char type.") );
    // Printable.c = va_arg( vl, char );
    Printable.c = list.get_parameter().get_value().c;
    list.pop();
    // printf_s( "%c\n", Printable.c );
    cout << Printable.c << endl;
    break;

    case 's':
    _ASSERT_EXPR( User_Type::eString_Type == list.get_parameter().get_type(), _TEXT("This current type is NOT string type.") );
    // Printable.s = va_arg( vl, char * );
    Printable.s = list.get_parameter().get_value().s;
    list.pop();
    // printf_s( "%s\n", Printable.s );
    cout << Printable.s << endl;
    break;

    default:
    break;
    }
    }
    // va_end( vl );
    }

    int main()
    {
    // ShowVar( "fcsi", 32.4f, 'a', "Test string", 4 );
    print( "fcsi", Float_Type( 32.4f ), Char_Type( 'a' ), String_Type( "Test string" ), Int_Type( 4 ));

    return 0;
    }
    Nephi Immortal, Dec 20, 2012
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Colin Walters
    Replies:
    2
    Views:
    509
    Ben Pfaff
    Feb 13, 2004
  2. Ross A. Finlayson
    Replies:
    19
    Views:
    583
    Keith Thompson
    Mar 10, 2005
  3. Replies:
    2
    Views:
    334
    Dave Thompson
    Feb 27, 2006
  4. Replies:
    5
    Views:
    355
  5. Heribert Weinrot

    Re:Variadic function can have type safety.

    Heribert Weinrot, Dec 23, 2012, in forum: C++
    Replies:
    0
    Views:
    217
    Heribert Weinrot
    Dec 23, 2012
Loading...

Share This Page