Making a wrapper templated

This is a discussion on Making a wrapper templated within the C++ Programming forums, part of the General Programming Boards category; Greetings, I'm kind of new to C++ and am having difficulty understanding subject I haven't explored thoroughly. Some kind souls ...

  1. #1
    Registered User DynV's Avatar
    Join Date
    Jul 2012
    Location
    Montreal, Canada
    Posts
    20

    Making a wrapper templated

    Greetings,

    I'm kind of new to C++ and am having difficulty understanding subject I haven't explored thoroughly. Some kind souls helped me for a side-project but it seems I've reached their patience threshold and am hoping you can provide me a bit more patience on the matter ; perhaps I'd be in luck to find people excited to show the subject.

    The purpose of this side-project if to have 2 ways of displaying a class. The algorithm behind those 2 display functions is quite similar but have a big impact on the object ; in fact it can very easily have a helper function which have a single Boolean parameter.

    I had much difficulty constructing the following from the hints that were provided to me and at the end, an especially generous IRC user completed the code correctly ; yielding this which display
    (blah)[blah]
    . I made some modifications simplifying it, so I wouldn't have to duplicate further modifications attempting to integrate template.
    Code:
    #include <iostream>
    #include <string>
    
    struct foowrapper2;
    
    class foo {
        std::string name;
    public:
        void setName(std::string iniName) {
            name = iniName;
        }
    //    std::string getName() const {
    //        return name;
    //    }
    friend std::ostream & operator<<(std::ostream &, foowrapper2 const &);
    friend foowrapper2 print2(foo const &);
    };
    
    struct foowrapper2 {
        foo const & objFoowrapper2;
    };
    
    foowrapper2 print2(foo const & objPrint2) {
        return {objPrint2}; // without curly brackets: error: conversion from ‘const foo’ to non-scalar type ‘foowrapper2’ requested
    }
    
    std::ostream & operator<<(std::ostream & lhs, foowrapper2 const & rhs) {
        lhs << '[' << rhs.objFoowrapper2.name << ']'; // rhs.objFoowrapper2.getName()
    }
    
    int main() {
        foo f;
        f.setName("blah");
    
        std::cout << print2(f);
    }
    which display
    [blah]
    At the time the wrapper code was given to me, I forgot to mention the object was in a template so today I asked some more help. I was told that as my object used a template, I need to make the wrapper templated. I got some pointers, making the appropriate modifications up to the last one which I couldn't get and exhausted their patience. Notice the commented error messages in the following:
    Code:
    #include <iostream>
    #include <string>
    
    template <typename T> class foo {
    public:
        T id;
        void setId(T iniName) {
            id = iniName;
        }
    };
    
    template <typename T> struct foowrapper {
        foo<T> const & objFoowrapper;
    };
    
    template <typename T> foowrapper print(foo<T> const & objprint) { // error: invalid use of template-name ‘foowrapper’ without an argument list
        return {objprint}; // without curly brackets: error: conversion from ‘const foo’ to non-scalar type ‘foowrapper’ requested
    }
    
    std::ostream & operator<<(std::ostream & lhs, foowrapper const & rhs) { // error: expected constructor, destructor, or type conversion before ‘&’ token
        lhs << '[' << rhs.objFoowrapper.id << ']';
    }
    
    int main() {
        foo<std::string> f;
        f.setId("blah");
    
        std::cout << print(f) << std::endl; // error: ‘print’ was not declared in this scope
    }
    I was told that as the wrapper contain
    Code:
    foo<int> const & objFoowrapper
    , it need to be instantiated. Well I don't understand, in the main function (at the bottom), I declared
    Code:
    foo<std::string> f;
    which I thought would be passed to the wrapper as there's a reference to it. I don't know what the reference mean between the wrapper and class, I only know it create some kind of relationship between them ; allowing to have a many-to-one relationship from wrapper to class.

    Thank you kindly for your help
    Last edited by DynV; 07-08-2012 at 09:38 PM. Reason: wans't highlighted in the preview, removed links

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,304
    Looking at your current code, I would probably do something like this:
    Code:
    template <typename T>
    struct foowrapper {
        foo<T> const & objFoowrapper;
    
        explicit foowrapper(foo<T> const & object) : objFoowrapper(object) {}
    private:
        void operator=(foowrapper<T> const & other);
    };
    
    template <typename T>
    foowrapper<T> print(foo<T> const & objprint) {
        return foowrapper<T>(objprint);
    }
    
    template<typename T>
    std::ostream & operator<<(std::ostream & lhs, foowrapper<T> const & rhs) {
        return lhs << '[' << rhs.objFoowrapper.id << ']';
    }
    Notice where I use foowrapper<T> instead of just foowrapper. Also, notice that I disabled the copy assignment operator for foowrapper and made the operator<< a function template, and actually returned the output stream.

    EDIT:
    Actually, looking at this again, I think your design is a little weird. Why not just write:
    Code:
    std::cout << foowrapper<std::string>(f) << std::endl;
    ? Or if you want to keep the print function template, then rename it to something like "wrap", or "wrapForBracketedDisplay".
    Last edited by laserlight; 07-08-2012 at 09:51 PM.
    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
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    Why not just overload operator<< and operator>> for foowrapper, then write
    I'd prefer the secondary interface function that "automagically" determines the types used in the expansion.

    some modifications simplifying it
    O_o

    If there is not a "One True Stream" view of your class consider not using the stream overloads at all.

    Code:
    Print1(std::cout, sMyFooInstance);
    Print2(std::cout, sMyFooInstance);
    Code:
    template
    <
        typename FContained
    >
    void Print1
    (
        std::ostream & fOut
      , const foo<FContained> & fData
    );
    
    template
    <
        typename FContained
    >
    void Print2
    (
        std::ostream & fOut
      , const foo<FContained> & fData
    );
    If there is a "One True Stream" only viewed as having different types of conceptual formatting use the facilities the library provides to do it properly.

    Code:
    struct SData{};
    
    int PrettyTypeIndex()
    {
        static const int sIndex = std::ios_base::xalloc();
        return(sIndex);
    }
    
    std::ostream & PrettyType1
    (
        std::ostream & fOut
    )
    {
        fOut.iword(PrettyTypeIndex()) = 1;
        return(fOut):
    }
    
    std::ostream & PrettyType2
    (
        std::ostream & fOut
    )
    {
        fOut.iword(PrettyTypeIndex()) = 2;
        return(fOut):
    }
    
    std::ostream & operator <<
    (
        std::ostream fRHS
      , const SData & fLHS
    )
    {
        int sPrettyType(fOut.iword(PrettyTypeIndex()));
        if(sPrettyType == 1)
        {
            // ...
        }
        else if(sPrettyType == 2)
        {
            // ...
        }
        return(fRHS);
    }
    That gives us a lot of "Look-and-Feel" for very little work.

    Code:
        SData sData;
        std::cout << PrettyType1 << sData << '\n';
        std::cout << PrettyType2 << sData << '\n';
    Soma

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,304
    Quote Originally Posted by photomap
    I'd prefer the secondary interface function that "automagically" determines the types used in the expansion.
    Yeah, I just realised that there might be some benefit to that, though renaming it would be better since it does not print anything by itself.
    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

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,415
    Yeah, I just realised that there might be some benefit to that, though renaming it would be better since it does not print anything by itself.
    *shrug*

    Well, my example `PrettyType1' isn't spectacular either...

    Soma

  6. #6
    Registered User DynV's Avatar
    Join Date
    Jul 2012
    Location
    Montreal, Canada
    Posts
    20
    Yes! I got it working. Looking at your code, I went for the signatures right away and found out the problem. My version:
    Code:
    #include <iostream>
    #include <string>
    
    template <typename T> class foo {
    public:
        T id;
        void setId(T iniName) {
            id = iniName;
        }
    };
    
    template <typename T> struct foowrapper {
        foo<T> const & objFoowrapper;
    };
    
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return {objprint}; // without curly brackets: error: conversion from ‘const foo’ to non-scalar type ‘foowrapper’ requested
    }
    
    template <typename T> std::ostream & operator<<(std::ostream & lhs, foowrapper<T> const & rhs) {
        lhs << '[' << rhs.objFoowrapper.id << ']';
    }
    
    int main() {
        foo<std::string> f;
        f.setId("blah");
        std::cout << print(f) << std::endl;
    
        foo<int> g;
        g.setId(147);
        std::cout << print(g) << std::endl;
        g.id *= 2;
        std::cout << print(g) << std::endl;
    }
    displaying
    [blah]
    [147]
    [294]
    Ugh! To think I had a version, before the unworking version, just like that then the person told me to remove
    , typename U
    and it went further and further away from the right path. Is having 2 typenames really a problem? If so I guess it's because the parameter type is "passed" to the retuen type in the template system.

    I see you made other modifications. I assume it's for print(), dropping the return-type from being wrapped by curly brackets ; I wonder what those are for. :| I assume the return is now casted and that the explicit is so the optimizer doesn't do its magic on the constructor. This is complicated for me but again, this is a side-project ; explanation would satisfy some curiosity but I don't think it's needed now that the wrapper is templated successfully.

  7. #7
    Registered User DynV's Avatar
    Join Date
    Jul 2012
    Location
    Montreal, Canada
    Posts
    20
    Quote Originally Posted by laserlight View Post
    EDIT:
    Actually, looking at this again, I think your design is a little weird. Why not just write:
    Code:
    std::cout << foowrapper<std::string>(f) << std::endl;
    ? Or if you want to keep the print function template, then rename it to something like "wrap", or "wrapForBracketedDisplay".
    I don't understand what you just wrote, I'm not so good (read not at all) with wrapper and templates. Again my project isn't so complicated, this is a side-project and I see it took me far beyound the scope of what I'll see in my project.

    Quote Originally Posted by phantomotap View Post
    Quote Originally Posted by DynV View Post
    some modifications simplifying it
    O_o
    I'm very sorry I assumed it was the content of my simplification, actually it was at the beginning of my forking from that but I forgot to save it. I suppose I could find it if I searched my backup but as I see it's not really a issue, I might as well save the time.

    Quote Originally Posted by phantomotap View Post
    If there is not a "One True Stream" view of your class consider not using the stream overloads at all.
    I considered making the display functions explicit, not allowing the usual operator<< overload to make sure the use would be awarer that there's an alternative.

    I assume the code your provided is a real simplification of the solution unfortunatelly I don't understand its syntax. :| Is there for that style?

    Quote Originally Posted by phantomotap View Post
    If there is a "One True Stream" only viewed as having different types of conceptual formatting use the facilities the library provides to do it properly.
    That's come cool code! What are the 2nd blocks following the usual 1st one for functions? std::ios_base::xalloc() Tthis surely is miles ahead of me. I don't see the declaration of PrettyTypeIndex() but perhaps I'm distracted. This is like string modifiers, I wonder what's the name? Plain modifier? I like this way better!
    Last edited by DynV; 07-08-2012 at 10:45 PM.

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    The syntax
    Code:
    return {objprint};
    is in fact part of the new C++ standard, C++11. The rest of your code is compatible with the old standard, so you probably want to avoid using it. When I compile with g++ 4.4 and g++ 4.6, I get this warning by default:
    Code:
    templated.cpp: In function ‘foowrapper<T> print(const foo<T>&)’:
    templated.cpp:17:5: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x [enabled by default]
    When I actually enable all warnings, I get more information:
    Code:
    $ g++ -Wall -Wextra templated.cpp -o templated
    templated.cpp: In function ‘foowrapper<T> print(const foo<T>&)’:
    templated.cpp:17:5: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x [enabled by default]
    templated.cpp: In function ‘std::ostream& operator<<(std::ostream&, const foowrapper<T>&)’:
    templated.cpp:22:1: warning: no return statement in function returning non-void [-Wreturn-type]
    The no return statement warning is because you don't have "return lhs;" in that function. So chaining this function together with multiple << operators would fail -- you're probably lucky it didn't segfault when you tried to put an "std::endl" after your print() calls.

    However... this is valid C++ (not using any C++11) and compiles without warnings:
    Code:
    $ cat templated.cpp 
    #include <iostream>
    #include <string>
     
    template <typename T> class foo {
    public:
        T id;
        void setId(T iniName) {
            id = iniName;
        }
    };
     
    template <typename T> struct foowrapper {
        foo<T> const & objFoowrapper;
    };
     
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return (foowrapper<T>){objprint};  // note cast
    }
     
    template <typename T> std::ostream & operator<<(std::ostream & lhs, foowrapper<T> const & rhs) {
        lhs << '[' << rhs.objFoowrapper.id << ']';
        return lhs;  // note return value
    }
     
    int main() {
        foo<std::string> f;
        f.setId("blah");
        std::cout << print(f) << std::endl;
     
        foo<int> g;
        g.setId(147);
        std::cout << print(g) << std::endl;
        g.id *= 2;
        std::cout << print(g) << std::endl;
    }
    $ g++ -Wall -Wextra templated.cpp -o templated
    $
    Of course, the more standard way to do this would be to create a constructor for foowrapper that takes a foo as a parameter. Then you can avoid the strange syntax
    Code:
    (foowrapper<T>){...}
    altogether, and just say "return objprint;". This will automatically construct a foowrapper for you (unless the constructor is marked explicit, in which case you could say "return foowrapper<T>(objprint);".

    My take on the problem: The functionality you're looking for is closely related to stream manipulators from the header file <iomanip>, e.g. "std::cout << std::hex << 55" will print 55 in hex, "std::cout << std::oct << 55" will print 55 in octal. I don't know precisely how these work but you could do something similar by introducing your own stream wrapper around std::cout (or around any standard stream, really).

    So here's my quick example.
    Code:
    #include <iostream>
    
    class Foo {
    private:
        int a, b, c;
    public:
        Foo(int a, int b, int c) : a(a), b(b), c(c) {}
        int getA() const { return a; }
        int getB() const { return b; }
        int getC() const { return c; }
    };
    
    class FooStream {
    public:
        enum FooPrintingMode {
            PRINT_NORMAL,
            PRINT_DETAILED
        };
    private:
        std::ostream &stream;
        FooPrintingMode mode;
    public:
        FooStream(std::ostream &stream) : stream(stream), mode(PRINT_NORMAL) {}
    
        // print normal types
        // (this is specialized to print Foo below)
        template <typename T>
        FooStream &operator << (const T &data) {
            stream << data;
            return *this;
        }
    
        // handle std::ostream manipulators
        // there are two others you need to supply to handle all cases, see
        // c++ - std::endl is of unknown type when overloading operator<< - Stack Overflow
        FooStream &operator << (std::ostream & (*m)(std::ostream &)) {
            m(stream);
            return *this;
        }
    
        // handle FooStream manipulators
        FooStream &operator << (FooStream & (*m)(FooStream &)) {
            return m(*this);
        }
    
        void setMode(FooPrintingMode mode) {
            this->mode = mode;
        }
    };
    
    // template specialization: how to print Foo
    template <>
    FooStream &FooStream::operator << <Foo>(const Foo &foo) {
        switch(mode) {
        case PRINT_NORMAL:
            stream << foo.getA();
            break;
        case PRINT_DETAILED:
            stream << "[foo " << static_cast<const void *>(&foo)
                << ' ' << foo.getA()
                << ',' << foo.getB()
                << ',' << foo.getC() << ']';
            break;
        }
        return *this;
    }
    
    // functors to set the foo-printing mode
    FooStream &normalFoo(FooStream &stream) {
        stream.setMode(FooStream::PRINT_NORMAL);
        return stream;
    }
    FooStream &detailedFoo(FooStream &stream) {
        stream.setMode(FooStream::PRINT_DETAILED);
        return stream;
    }
    
    int main() {
        Foo one(1, 2, 3);
        Foo two(11, 22, 33);
    
        FooStream stream(std::cout);
        stream << normalFoo << one << std::endl;
        stream << detailedFoo << two << std::endl;
    
        return 0;
    }
    Sorry it's so complicated, I went a little overboard. The part to handle std::ostream manipulators is so that you can use std::endl. The output is
    Code:
    1
    [foo 0x7ffffb4c9a00 11,22,33]
    i.e. "one" is printed with mode PRINT_NORMAL, and "two" is printed with mode PRINT_DETAILED. I guess real std::ostream manipulators behave a bit differently, since
    Code:
    std::cout << std::hex << 5;
    std::cout << 6;
    sets a "hex" property that disappears by the time the second cout statement is invoked, whereas my implementation will set a property of the stream that stays set... but that's a minor point I guess.

    You probably won't want to use my code if you're not too familiar with this stuff but it might be interesting to look at. Also, I wanted to say hi to a fellow Canadian! I don't speak French unfortunately, but it's good to see some Canadians using this forum.
    Last edited by dwks; 07-08-2012 at 11:29 PM. Reason: weird :o smilies, syntax highlighting!
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #9
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,762
    I'm pretty sure that manipulators of all sorts are simply objects, with their own extraction and insertion operators, and all of them having been instantiated, either with existing names or as a temporary anonymous object. The operators of the manipulators have to prepare the stream to do whatever.

    Perhaps it isn't as artful but I would just do:
    Code:
    Foo f;
    f.detailNeeded(Foo::Verbose);
    cout << f << endl;
    f.detailNeeded(Foo::Terse);
    cout << f << endl;
    f.detailNeeded(Foo::DefaultDetail);
    I think largely the only reason that std::hex and the like were even provided was because numerical types are primitives, and not even implemented as primitive objects*. That means that printing a certain way was necessarily made a streaming problem. The code artist in me says that the level of Foo detail is Foo's business, though.

    * Though, the behavior of the compiler will set out to make me sort of wrong, since the compiler can generate constructors for POD types, according to various standards.

  10. #10
    Registered User DynV's Avatar
    Join Date
    Jul 2012
    Location
    Montreal, Canada
    Posts
    20
    I appreciate your long post dwks. I wanted to reply yesterday, not long after the others replied but by then I was worn out, funny what a few minutes can do. Your nickname seem familiar ; do you hand out on freenode?

    Quote Originally Posted by dwks View Post
    The syntax
    Code:
    return {objprint};
    is in fact part of the new C++ standard, C++11.
    Do you know the name for it, so I can search for it and know what that weird thing do.

    Quote Originally Posted by dwks View Post
    However... this is valid C++ (not using any C++11) and compiles without warnings:
    Code:
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return (foowrapper<T>){objprint};  // note cast
    }
    Of course, the more standard way to do this would be to create a constructor for foowrapper that takes a foo as a parameter. Then you can avoid the strange syntax
    Code:
    (foowrapper<T>){...}
    altogether, and just say "return objprint;". This will automatically construct a foowrapper for you (unless the constructor is marked explicit, in which case you could say "return foowrapper<T>(objprint);".
    Thanks for explaining what I didn't get from laserlight code and for pointing me what was the problem with my previous version on the online compiler ideone, currently using gcc-4.3.4, which the IRC channel I refered to previously uses: freenode ##c++-basic. Although on my system: with cygwin, gcc version 4.5.3 (GCC), it compiles (so no errors, just warnings) and with MinGW, gcc version 3.4.5 (mingw-vista special r3), it gives similar errors:
    Code:
    test-wrapper-template.cpp||In function `foowrapper<T> print(const foo<T>&)':|
    test-wrapper-template.cpp|19|error: expected primary-expression before '{' token|
    test-wrapper-template.cpp|19|error: expected `;' before '{' token|
    test-wrapper-template.cpp|19|error: expected `;' before '}' token|
    test-wrapper-template.cpp||In function `std::ostream& operator<<(std::ostream&, const foowrapper<T>&)':|
    test-wrapper-template.cpp|24|warning: no return statement in function returning non-void|
    test-wrapper-template.cpp||In function `foowrapper<T> print(const foo<T>&) [with T = std::string]':|
    test-wrapper-template.cpp|29|instantiated from here|
    test-wrapper-template.cpp|19|warning: statement has no effect|
    test-wrapper-template.cpp||In function `foowrapper<T> print(const foo<T>&) [with T = int]':|
    test-wrapper-template.cpp|33|instantiated from here|
    test-wrapper-template.cpp|19|warning: statement has no effect|
    ||=== Build finished: 3 errors, 3 warnings ===|
    Quote Originally Posted by dwks View Post

    My take on the problem: The functionality you're looking for is closely related to stream manipulators from the header file <iomanip>, e.g. "std::cout << std::hex << 55" will print 55 in hex, "std::cout << std::oct << 55" will print 55 in octal. I don't know precisely how these work but you could do something similar by introducing your own stream wrapper around std::cout (or around any standard stream, really).
    It was my 1st idea but I thought as the object didn't modify the content itself, I should find some other way to do so. The 2 ways of displaying will yeild the same result, but one modifies the object with the other don't ; so one have operator<< rhs parameter & while the other const &.

    Quote Originally Posted by dwks View Post
    So here's my quick example.
    [...]
    You probably won't want to use my code if you're not too familiar with this stuff but it might be interesting to look at.
    This is neat code although I don't understand it all ; I like modifiers. The thing I don't see in that code is that different data types have to be used, perhaps it's the case but from the little I understand from it, I don't see it happening ; by different data types, I mean just like in the main() of the code your reworked for me, I use string and int.

    Quote Originally Posted by dwks View Post
    Also, I wanted to say hi to a fellow Canadian! I don't speak French unfortunately, but it's good to see some Canadians using this forum.
    Well I hope you're not offended if I'm so strong on being called a Canadian, I put the country in location as it's more recognizable on the international level. I like Canada for the part I've seen, I just dislike the constant battles our 2 parliament (federal & provincial) has, which at some point got quite fierce. I wish it would stop and there's only 2 ways I see it happening, I prefer the softer one but the other is better than keep fighting. I hope us being fellow coders will be more important than us sharing nationalism.
    Last edited by DynV; 07-10-2012 at 12:11 AM.

  11. #11
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Quote Originally Posted by DynV View Post
    I appreciate your long post dwks. I wanted to reply yesterday, not long after the others replied but by then I was worn out, funny what a few minutes can do. Your nickname seem familiar ; do you hand out on freenode?
    Not very often, especially these days, but you may have seen me there. I tend to prefer forums.

    Do you know the name for it, so I can search for it and know what that weird thing do.
    Based on the error message I would say "extended initializer lists". This page gives a quick description: it seems that the curly-braces are a unified initialization syntax in C++11. C++11 FAQ

    Thanks for explaining what I didn't get from laserlight code and for pointing me what was the problem with my previous version on the online compiler ideone, currently using gcc-4.3.4, which the IRC channel I refered to previously uses: freenode ##c++-basic. Although on my system: with cygwin, gcc version 4.5.3 (GCC), it compiles (so no errors, just warnings) and with MinGW, gcc version 3.4.5 (mingw-vista special r3), it gives similar errors:
    ...
    I expect modern versions of gcc to support this syntax. You'll get warnings if it is supported and errors if the compiler just doesn't know what you are doing. At a guess, this page says "initializer lists" were introduced in gcc 4.4, which I believe fits with your observations.

    It was my 1st idea but I thought as the object didn't modify the content itself, I should find some other way to do so. The 2 ways of displaying will yeild the same result, but one modifies the object with the other don't ; so one have operator<< rhs parameter & while the other const &.
    Normally a single function with a const& parameter is good enough. Any reference will be converted to a const reference implicitly. Sometimes you need two functions, but usually only when e.g. the return value differs:
    Code:
    SomeClass &getData() { return data; }
    const SomeClass &getData() const { return data; }
    That would allow anyone with a const& reference to only get a const SomeClass& reference back, while with a non-const reference you could get either. The standard libraries use this for accessors, among other things. (If I have a vector v and I say v[3], I can write to that location if and only if my v reference is non-const.)

    This is neat code although I don't understand it all ; I like modifiers. The thing I don't see in that code is that different data types have to be used, perhaps it's the case but from the little I understand from it, I don't see it happening ; by different data types, I mean just like in the main() of the code your reworked for me, I use string and int.
    No, I did not include support for different data types. I was mostly trying to make a solution that used manipulators. The other comments in this thread would probably lead to nicer designs. If you have specific questions about how it works, please ask.

    As I reread this thread I realized something I might have been missing. Are you just trying to print a Foo differently when it's a Foo<int> than when it's a Foo<string>? That's pretty easy to do:
    Code:
    #include <iostream>
    #include <string>
    
    template <typename Type>
    class Foo {
    private:
        Type value;
    public:
        Foo(Type value) : value(value) {}
        Type get() const { return value; }
    };
    
    // template prototype for Foo<> printing functions.
    // This would go in the header file, and if you don't supply a version of
    // the function for each type (or a default version that handles all types),
    // then you may get linker errors.
    template <typename Type>
    std::ostream &operator << (std::ostream &stream, const Foo<Type> &foo);
    
    // template specialization for type Foo<int>
    template <>
    std::ostream &operator << (std::ostream &stream, const Foo<int> &foo) {
        stream << "[Foo<int> " << foo.get() << "]";
        return stream;
    }
    
    // template specialization for type Foo<std::string>
    template <>
    std::ostream &operator << (std::ostream &stream, const Foo<std::string> &foo) {
        stream << "(Foo<string> " << foo.get() << ")";
        return stream;
    }
    
    int main() {
        Foo<int> intFoo(42);
        Foo<std::string> stringFoo("hello!");
        
        std::cout << intFoo << std::endl;
        std::cout << stringFoo << std::endl;
        
        return 0;
    }
    Well I hope you're not offended if I'm so strong on being called a Canadian, I put the country in location as it's more recognizable on the international level. I like Canada for the part I've seen, I just dislike the constant battles our 2 parliament (federal & provincial) has, which at some point got quite fierce. I wish it would stop and there's only 2 ways I
    see it happening, I prefer the softer one but the other is better than keep fighting. I hope us being fellow coders will be more important than us sharing nationalism.
    Well, it's not that important -- I just noticed your location as I was typing my post. The main thing that matters on CBoard is whether you can ask good questions.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Quote Originally Posted by dwks View Post
    However... this is valid C++ (not using any C++11) and compiles without warnings:
    Code:
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return (foowrapper<T>){objprint};  // note cast
    }
    That's a C99 compound literal, not valid C++. It won't compile on a compiler that doesn't support compound literals, like MSVC. It also won't compile on GCC if you compile with -std=c++03 -pedantic -Werror.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,048
    Hmm, you're right. I'm sorry. I knew it was part of C99 and I thought they must have put it into C++ as well, but I didn't try -pedantic. (The warning actually shows up with just "g++ -pedantic templated.cpp".)

    I guess using constructor-syntax is the way to go.
    Code:
    template <typename T> struct foowrapper {
        foowrapper(foo<T> foo) : objFoowrapper(foo) {}
        foo<T> const & objFoowrapper;
    };
     
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return foowrapper<T>(objprint);
    }
    // ...
    Not a peep from "g++ -Wall -Wextra -ansi -pedantic templated-fixed.cpp -o templated" this time. Of course. It's just a normal templated class now.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  14. #14
    Registered User DynV's Avatar
    Join Date
    Jul 2012
    Location
    Montreal, Canada
    Posts
    20
    Quote Originally Posted by dwks View Post
    it seems that the curly-braces are a unified initialization syntax in C++11. C++11 FAQ
    It's not just you! http://www2.research.att.com looks down from here. Check another site?


    I assume it was similar to Brace Initialization syntax - C++ Forum but I,ll have to just keep that in mind for now because I don't get it. I'll take a look when (if) I get this good.

    Quote Originally Posted by dwks View Post
    this page says "initializer lists" were introduced in gcc 4.4, which I believe fits with your observations.
    Cool page, thanks.

    Quote Originally Posted by dwks View Post
    [...] That would allow anyone with a const& reference to only get a const SomeClass& reference back, while with a non-const reference you could get either. [...]
    Hmm! I'm not sure what you're getting at but I was refering to operator<<(). I'm sure you had good intentions but I'm not good with wrappers nor templates.

    Quote Originally Posted by dwks View Post
    [...] The other comments in this thread would probably lead to nicer designs. [...]
    That's what I thought as I tried to convey that in my last message. I know my English isn't always good but that's not only about unfamiliarity. I sometimes have a hard time writing in my main language. My next reply (in this post) should help.

    Quote Originally Posted by dwks View Post
    As I reread this thread I realized something I might have been missing. Are you just trying to print a Foo differently when it's a Foo<int> than when it's a Foo<string>?
    I hope I'll make more sense now. To me a string modifier should only be made when the output actually change between 2 modes. What I'm looking for has the same display for the 2 modes although they have different effect on the object ; 1st doesn't change the object, like a good bulk of display functions, the 2nd also change the object, so it's in essence
    Code:
    function2() { function1(); makeChanges(); }
    Quote Originally Posted by dwks View Post
    Hmm, you're right. I'm sorry. I knew it was part of C99 and I thought they must have put it into C++ as well, but I didn't try -pedantic. (The warning actually shows up with just "g++ -pedantic templated.cpp".)

    I guess using constructor-syntax is the way to go.
    Code:
    template <typename T> struct foowrapper {
        foowrapper(foo<T> foo) : objFoowrapper(foo) {}
        foo<T> const & objFoowrapper;
    };
     
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return foowrapper<T>(objprint);
    }
    // ...
    Not a peep from "g++ -Wall -Wextra -ansi -pedantic templated-fixed.cpp -o templated" this time. Of course. It's just a normal templated class now.
    Well, I tried to apply the changes but the results were not really functional.
    Code:
    #include <iostream>
    #include <string>
    
    template <typename T> class foo {
    public:
        T id;
        void setId(T iniName) {
            id = iniName;
        }
        T getId() {
            return id;
        }
    };
    
    template <typename T> struct foowrapper {
        foowrapper(foo<T> foo) : objFoowrapper(foo) {}
        foo<T> const & objFoowrapper;
    };
    
    template <typename T> foowrapper<T> print(foo<T> const & objprint) {
        return foowrapper<T>(objprint); // without curly brackets: error: conversion from ‘const foo’ to non-scalar type ‘foowrapper’ requested
    }
    
    template <typename T> std::ostream & operator<<(std::ostream & lhs, foowrapper<T> const & rhs) {
        lhs << '[' << rhs.objFoowrapper.id << ']';
        return lhs;
    }
    
    int main() {
        foo<std::string> f;
        f.setId("blah");
        std::cout << "foo::getId()=" << f.getId() << "; \tprint(foo<T> const &)=" << print(f) << std::endl;
        f.setId("hello");
        std::cout << "foo::getId()=" << f.getId() << "; \tprint(foo<T> const &)=" << print(f) << std::endl;
    
        foo<int> g;
        g.setId(147);
        std::cout << "foo::getId()=" << g.getId() << "; \tprint(foo<T> const &)=" << print(g) << std::endl;
        g.setId(2547);
        std::cout << "foo::getId()=" << g.getId() << "; \tprint(foo<T> const &)=" << print(g) << std::endl;
    }
    With Cygwin (see #10 for versions), I got:
    foo::getId()=blah; print(foo<T> const &)=[blah]
    foo::getId()=hello; print(foo<T> const &)=[hello]
    foo::getId()=147; print(foo<T> const &)=[1816657920]
    foo::getId()=2547; print(foo<T> const &)=[1816657920]

    Process returned 0 (0x0) execution time : 0.128 s
    And with MinGW:
    foo::getId()=blah; print(foo<T> const &)=[
    Process returned -1073741819 (0xC0000005) execution time : 6.134 s

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. My Win32 wrapper
    By dxfoo in forum Windows Programming
    Replies: 10
    Last Post: 07-02-2010, 11:09 AM
  2. Templated Classes with Templated Functions
    By -EquinoX- in forum C++ Programming
    Replies: 9
    Last Post: 11-22-2009, 10:44 PM
  3. Creating wrapper for C++ DLL
    By steve1_rm in forum C# Programming
    Replies: 2
    Last Post: 06-10-2008, 08:49 PM
  4. DLL Wrapper
    By vampirekiss in forum C Programming
    Replies: 4
    Last Post: 01-08-2008, 10:24 AM
  5. Different approaches to making a Win32 wrapper
    By xds4lx in forum Windows Programming
    Replies: 16
    Last Post: 02-27-2002, 04:49 PM

Tags for this Thread


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