Templated Classes question (what to do with char*)

Discussion in 'C++' started by Robert.Holic@gmail.com, Feb 4, 2007.

  1. Guest

    Hi All (first time caller, long time listener),


    I've stumbled across a problem that I have yet to figure out,
    although Im sure I'll kick myself when I figure it out. Here it is:

    I need to create a templated class that accepts any type. Easy
    enough I though, like this:

    template<typename Type>
    class Foo
    {
    Type data;
    Foo(Type d){ data = d);
    ~Foo(void){}
    void SetData(Type d){ data = d; }
    }

    But what if the type is char*? Is there a way I can tell it is and
    therefore strcpy into data instead of straight copy of the pointer so
    that when the inputted string into SetData loses scope I can retain
    it? Hopefully that makes sense. Thanks!
     
    , Feb 4, 2007
    #1
    1. Advertising

  2. Kai-Uwe Bux Guest

    wrote:

    > Hi All (first time caller, long time listener),
    >
    >
    > I've stumbled across a problem that I have yet to figure out,
    > although Im sure I'll kick myself when I figure it out. Here it is:
    >
    > I need to create a templated class that accepts any type. Easy
    > enough I though, like this:
    >
    > template<typename Type>
    > class Foo
    > {
    > Type data;
    > Foo(Type d){ data = d);


    I would prefer initialization:

    Foo ( Type d )
    : data ( d )
    {}

    > ~Foo(void){}
    > void SetData(Type d){ data = d; }


    Setter and Getter functions are usually a smell.

    > }


    missing ";"


    > But what if the type is char*? Is there a way I can tell it is and
    > therefore strcpy into data instead of straight copy of the pointer so
    > that when the inputted string into SetData loses scope I can retain
    > it? Hopefully that makes sense.


    Sure does: You can use a partial specialization:

    template <>
    class Foo< char* > {

    char* data;

    Foo ( char* str ) :
    : data ( new char [ strlen( str ) + 1 ] )
    //FIXME: maybe off by one
    {
    strcpy( I forgot the argument order )
    // FIXME: I don't know whether strcpy takes care of terminating 0.
    }

    ...

    };

    or something like that.

    Note however, that

    a) you would need to do this for signed char and unsigned char, too.
    b) The default implementation is very likely to do the wrong thing for any
    pointer type.


    You might want to have a look into enable_if and disable_if from boost to
    see whether you can prevent Foo<T*> to be instantiated for any T but
    char/signed char/unsigned char.



    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Feb 4, 2007
    #2
    1. Advertising

  3. Guest

    On Feb 3, 8:54 pm, Kai-Uwe Bux <> wrote:
    > wrote:
    > > Hi All (first time caller, long time listener),

    >
    > > I've stumbled across a problem that I have yet to figure out,
    > > although Im sure I'll kick myself when I figure it out. Here it is:

    >
    > > I need to create a templated class that accepts any type. Easy
    > > enough I though, like this:

    >
    > > template<typename Type>
    > > class Foo
    > > {
    > > Type data;
    > > Foo(Type d){ data = d);

    >
    > I would prefer initialization:
    >
    > Foo ( Type d )
    > : data ( d )
    > {}
    >
    > > ~Foo(void){}
    > > void SetData(Type d){ data = d; }

    >
    > Setter and Getter functions are usually a smell.
    >
    > > }

    >
    > missing ";"
    >
    > > But what if the type is char*? Is there a way I can tell it is and
    > > therefore strcpy into data instead of straight copy of the pointer so
    > > that when the inputted string into SetData loses scope I can retain
    > > it? Hopefully that makes sense.

    >
    > Sure does: You can use a partial specialization:
    >
    > template <>
    > class Foo< char* > {
    >
    > char* data;
    >
    > Foo ( char* str ) :
    > : data ( new char [ strlen( str ) + 1 ] )
    > //FIXME: maybe off by one
    > {
    > strcpy( I forgot the argument order )
    > // FIXME: I don't know whether strcpy takes care of terminating 0.
    > }
    >
    > ...
    >
    > };
    >
    > or something like that.
    >
    > Note however, that
    >
    > a) you would need to do this for signed char and unsigned char, too.
    > b) The default implementation is very likely to do the wrong thing for any
    > pointer type.
    >
    > You might want to have a look into enable_if and disable_if from boost to
    > see whether you can prevent Foo<T*> to be instantiated for any T but
    > char/signed char/unsigned char.
    >
    > Best
    >
    > Kai-Uwe Bux


    I dont understand, by doing the partial specialization anytime I made
    a class Foo<char*> it would use that specialization and any other time
    it would use Foo<Type>. Is that what you mean? So basically hard code
    the template function for types that are pointers?
     
    , Feb 4, 2007
    #3
  4. Jerry Coffin Guest

    In article <>,
    says...
    > Hi All (first time caller, long time listener),
    >
    >
    > I've stumbled across a problem that I have yet to figure out,
    > although Im sure I'll kick myself when I figure it out. Here it is:
    >
    > I need to create a templated class that accepts any type. Easy
    > enough I though, like this:
    >
    > template<typename Type>
    > class Foo
    > {
    > Type data;
    > Foo(Type d){ data = d);
    > ~Foo(void){}
    > void SetData(Type d){ data = d; }
    > }
    >
    > But what if the type is char*? Is there a way I can tell it is and
    > therefore strcpy into data instead of straight copy of the pointer so
    > that when the inputted string into SetData loses scope I can retain
    > it? Hopefully that makes sense. Thanks!


    Sure -- you can explicitly specialize your template over type char *,
    and have the explicit specialization do the right thing. You'd start
    with the code above (after fixing typos, such as in the ctor), and then
    add an explicit specialization:

    template<>
    class Foo<char *> {
    // ...
    };

    Making this code exception safe WILL be decidedly non-trivial. Unless
    you're quite experienced with exception safety, I'd recommend reading
    items 8-13 of _Exceptional C++_ before you implement this code.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Feb 4, 2007
    #4
  5. Jerry Coffin Guest

    In article <eq3eci$2m$>,
    says...

    [ ... ]

    > Sure does: You can use a partial specialization:
    >
    > template <>
    > class Foo< char* > {


    Just a minor note on terminology: this is an explicit specialization. A
    partial specialization is...partial. For example:

    template <class T, class U>
    class Foo {
    // ...
    };

    template <class T>
    class Foo<char> {
    // ...
    };

    In this case, the specialization is only partial -- one parameter has a
    specified type, but the other is still generic. You can only partially
    specialize a template that has at least two template parameters.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Feb 4, 2007
    #5
  6. Guest

    On Feb 3, 9:27 pm, Jerry Coffin <> wrote:
    > In article <eq3eci$>,
    > says...
    >
    > [ ... ]
    >
    > > Sure does: You can use a partial specialization:

    >
    > > template <>
    > > class Foo< char* > {

    >
    > Just a minor note on terminology: this is an explicit specialization. A
    > partial specialization is...partial. For example:
    >
    > template <class T, class U>
    > class Foo {
    > // ...
    >
    > };
    >
    > template <class T>
    > class Foo<char> {
    > // ...
    >
    > };
    >
    > In this case, the specialization is only partial -- one parameter has a
    > specified type, but the other is still generic. You can only partially
    > specialize a template that has at least two template parameters.
    >
    > --
    > Later,
    > Jerry.
    >
    > The universe is a figment of its own imagination.


    Thank you very much. You guys were extremely helpful and clear. Cheers
     
    , Feb 4, 2007
    #6
  7. Daniel T. Guest

    wrote:

    > I've stumbled across a problem that I have yet to figure out,
    > although Im sure I'll kick myself when I figure it out. Here it is:
    >
    > I need to create a templated class that accepts any type. Easy
    > enough I though, like this:
    >
    > template<typename Type>
    > class Foo
    > {
    > Type data;
    > Foo(Type d){ data = d);
    > ~Foo(void){}
    > void SetData(Type d){ data = d; }
    > }
    >
    > But what if the type is char*?


    Don't do that. Use std::string instead.

    > Is there a way I can tell it is and therefore strcpy into data
    > instead of straight copy of the pointer so that when the inputted
    > string into SetData loses scope I can retain it?


    Yes there is a way to do that, but it opens up the question, what about
    pointers to other things?

    template< typename Type >
    class Foo
    {
    Type data;
    public:
    Foo( Type d ) {
    data = d;
    }
    ~Foo() { }

    void SetData( Type d ) {
    data = d;
    }
    };

    template<>
    class Foo < char* >
    {
    char* data;
    public:
    Foo( const char* d ): data( 0 ) {
    SetData( d );
    }
    Foo( const Foo& o ): data( 0 ) {
    SetData( o.data );
    }
    ~Foo() {
    delete [] data;
    }
    Foo& operator=( const Foo& o ) {
    SetData( o.data );
    return *this;
    }
    void SetData( const char* d ) {
    char* tmp = data;
    data = new char[ strlen( d ) ];
    strcpy( data, d );
    delete [] tmp;
    }
    };
     
    Daniel T., Feb 4, 2007
    #7
  8. Daniel T. Guest

    In article <>,
    "Daniel T." <> wrote:

    > template<>
    > class Foo < char* >
    > {
    > char* data;
    > public:
    > Foo( const char* d ): data( 0 ) {
    > SetData( d );
    > }
    > Foo( const Foo& o ): data( 0 ) {
    > SetData( o.data );
    > }
    > ~Foo() {
    > delete [] data;
    > }
    > Foo& operator=( const Foo& o ) {
    > SetData( o.data );
    > return *this;
    > }
    > void SetData( const char* d ) {
    > char* tmp = data;
    > data = new char[ strlen( d ) ];
    > strcpy( data, d );
    > delete [] tmp;
    > }
    > };


    I was caught by the off-by-one error in SetData. It should be "data =
    new char[ strlen( d ) + 1 ];" Yet another reason to use std::string.
     
    Daniel T., Feb 4, 2007
    #8
  9. Alan Johnson Guest

    wrote:
    > On Feb 3, 8:54 pm, Kai-Uwe Bux <> wrote:
    >> wrote:
    >>> Hi All (first time caller, long time listener),
    >>> I've stumbled across a problem that I have yet to figure out,
    >>> although Im sure I'll kick myself when I figure it out. Here it is:
    >>> I need to create a templated class that accepts any type. Easy
    >>> enough I though, like this:
    >>> template<typename Type>
    >>> class Foo
    >>> {
    >>> Type data;
    >>> Foo(Type d){ data = d);

    >> I would prefer initialization:
    >>
    >> Foo ( Type d )
    >> : data ( d )
    >> {}
    >>
    >>> ~Foo(void){}
    >>> void SetData(Type d){ data = d; }

    >> Setter and Getter functions are usually a smell.
    >>
    >>> }

    >> missing ";"
    >>
    >>> But what if the type is char*? Is there a way I can tell it is and
    >>> therefore strcpy into data instead of straight copy of the pointer so
    >>> that when the inputted string into SetData loses scope I can retain
    >>> it? Hopefully that makes sense.

    >> Sure does: You can use a partial specialization:
    >>
    >> template <>
    >> class Foo< char* > {
    >>
    >> char* data;
    >>
    >> Foo ( char* str ) :
    >> : data ( new char [ strlen( str ) + 1 ] )
    >> //FIXME: maybe off by one
    >> {
    >> strcpy( I forgot the argument order )
    >> // FIXME: I don't know whether strcpy takes care of terminating 0.
    >> }
    >>
    >> ...
    >>
    >> };
    >>
    >> or something like that.
    >>
    >> Note however, that
    >>
    >> a) you would need to do this for signed char and unsigned char, too.
    >> b) The default implementation is very likely to do the wrong thing for any
    >> pointer type.
    >>
    >> You might want to have a look into enable_if and disable_if from boost to
    >> see whether you can prevent Foo<T*> to be instantiated for any T but
    >> char/signed char/unsigned char.
    >>
    >> Best
    >>
    >> Kai-Uwe Bux

    >
    > I dont understand, by doing the partial specialization anytime I made
    > a class Foo<char*> it would use that specialization and any other time
    > it would use Foo<Type>. Is that what you mean? So basically hard code
    > the template function for types that are pointers?
    >


    If you have a general solution for any pointer type, you can use partial
    specialization to get just pointer types:

    template <typename Type>
    class Foo
    {
    // implementation goes here.
    } ;

    template <typename Type>
    class Foo<Type *>
    {
    // implementation for pointer types goes here.
    } ;

    // Not necessary if the above would work for char *.
    template <>
    class Foo<char *>
    {
    // implementation for char * goes here.
    } ;

    --
    Alan Johnson
     
    Alan Johnson, Feb 4, 2007
    #9
  10. Guest


    > If you have a general solution for any pointer type, you can use partial
    > specialization to get just pointer types:
    >
    > template <typename Type>
    > class Foo
    > {
    > // implementation goes here.
    >
    > } ;
    >
    > template <typename Type>
    > class Foo<Type *>
    > {
    > // implementation for pointer types goes here.
    >
    > } ;
    >
    > // Not necessary if the above would work for char *.
    > template <>
    > class Foo<char *>
    > {
    > // implementation for char * goes here.
    >
    > } ;
    >
    > --
    > Alan Johnson- Hide quoted text -
    >
    > - Show quoted text -



    > // Not necessary if the above would work for char *.


    It still seems to me that you would need to specify the char* aside
    from the pointer implementation . Maybe thats what you mean and a
    typo, not sure.
     
    , Feb 4, 2007
    #10
  11. Alan Johnson Guest

    wrote:
    >> If you have a general solution for any pointer type, you can use partial
    >> specialization to get just pointer types:
    >>
    >> template <typename Type>
    >> class Foo
    >> {
    >> // implementation goes here.
    >>
    >> } ;
    >>
    >> template <typename Type>
    >> class Foo<Type *>
    >> {
    >> // implementation for pointer types goes here.
    >>
    >> } ;
    >>
    >> // Not necessary if the above would work for char *.
    >> template <>
    >> class Foo<char *>
    >> {
    >> // implementation for char * goes here.
    >>
    >> } ;
    >>
    >> --
    >> Alan Johnson- Hide quoted text -
    >>
    >> - Show quoted text -

    >
    >
    >> // Not necessary if the above would work for char *.

    >
    > It still seems to me that you would need to specify the char* aside
    > from the pointer implementation . Maybe thats what you mean and a
    > typo, not sure.
    >


    The comment was just meant to imply that C++ wouldn't require you to
    have the explicit specialization. I've no idea what specific problem
    you are trying to solve. It may be that your solution for a Type * (for
    some generic Type) would also work for a a char *, in which case you
    would not need an explicit specialization for char *. If that is not
    the case, then you do, of course, need the explicit specialization for
    char *.

    --
    Alan Johnson
     
    Alan Johnson, Feb 4, 2007
    #11
  12. Grizlyk Guest

    :
    >
    > I need to create a templated class that accepts any type. Easy
    > enough I though, like this:
    >
    > But what if the type is char*? Is there a way I can tell it is and
    > therefore strcpy into data instead of straight copy of the pointer so
    > that when the inputted string into SetData loses scope I can retain
    > it? Hopefully that makes sense. Thanks!


    Any type will work with your templated class. But as i can understand, you
    want to manage any object pointer point to - copy if pointer copying, delete
    if pointer deleted etc. C++ type "pointer" does not allow it. There are
    special classes, that can do it - common wrappers as auto_ptr or special for
    "char*" classes as cstring. Use the classes as parameters instead of POD
    pointers.

    --
    Maksim A. Polyanin

    "In thi world of fairy tales rolls are liked olso"
    /Gnume/
     
    Grizlyk, Feb 8, 2007
    #12
  13. writes:
    > I need to create a templated class that accepts any type. Easy
    > enough I though, like this:
    >
    > template<typename Type>
    > class Foo
    > {
    > Type data;
    > Foo(Type d){ data = d);
    > ~Foo(void){}
    > void SetData(Type d){ data = d; }
    > }
    >
    > But what if the type is char*? Is there a way I can tell it is and
    > therefore strcpy into data instead of straight copy of the pointer so
    > that when the inputted string into SetData loses scope I can retain
    > it?


    You can use another class as template's parameter which specifies
    copying functions and specializations, ie.:

    #v+
    template<class T>
    class foo_copier {
    static void init(T &dest, const T&src) {
    dest = src;
    }

    static void copy(T &dest, const T&src) {
    dest = src;
    }

    static void done(T &dest) {
    /* nothing */
    }
    };

    template<>
    class foo_copier<char *> {
    static void init(T &dest, const T&src) {
    dest = 0;
    copy(dest, src);
    }

    static void copy(T &dest, const T&src) {
    delete[] dest;
    size_t len = strlen(src) + 1;
    dest = new char[len];
    memcpy(dest, src, len);
    }

    static void done(T &dest) {
    delete[] dest;
    }
    };
    #v-

    and then your class would look like:

    #v+
    template<class T, class copier = foo_copier<T> >
    class Foo {
    T data;
    public:
    Foo(const T &d) {
    copier::init(data, d);
    }

    ~Foo() {
    copier::done(data);
    }

    void setData(const T &d) {
    copier::copy(data, d);
    }
    };
    #v-

    This way users could define their own copier classes with their own
    chosen behaviour. Note however, that some compilers do not support
    default template arguments (ie. the part " = foo_copier<T> ").

    --
    Best regards, _ _
    .o. | Liege of Serenly Enlightened Majesty of o' \,=./ `o
    ..o | Computer Science, Michal "mina86" Nazarewicz (o o)
    ooo +--<mina86*tlen.pl>---<jid:mina86*chrome.pl>--ooO--(_)--Ooo--
     
    Michal Nazarewicz, Feb 13, 2007
    #13
    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. RA Scheltema
    Replies:
    3
    Views:
    424
    RA Scheltema
    Jan 6, 2004
  2. Marijn
    Replies:
    5
    Views:
    490
    Marijn
    Feb 13, 2004
  3. Replies:
    0
    Views:
    2,283
  4. lovecreatesbeauty
    Replies:
    1
    Views:
    1,155
    Ian Collins
    May 9, 2006
  5. Amadeus W. M.
    Replies:
    2
    Views:
    416
    Amadeus W. M.
    Jul 4, 2006
Loading...

Share This Page