Thread: stream-like-behavior problem

  1. #1
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937

    stream-like-behavior problem

    Hello. I want to write an initializer list method. I'm looking for the form:
    Code:
    std::stl_containter<double> thing = initializer<<43.4<<22233.43<<12.32;
    Simple enough, right? I am getting an error whenever I string more than one value on.
    Code:
    oop.cpp: In function ‘int main()’:
    oop.cpp:40: error: no match for ‘operator<<’ in ‘operator<<(dummy_type&, const T&) [with T = int](((const int&)((const int*)(&14)))) << 15’
    oop.cpp:32: note: candidates are: init_type<T>& operator<<(init_type<T>&, const T&) [with T = int]
    And here's the code, only slightly reduced:
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
    
    template<class T>
    class init_type
    {
        vector<T> v;
      public:
        operator vector<T>()
        {
    	return v;
        }
       //and similarly for list, valarray,etc.
        void push_back(const T & a) { v.push_back(a); }
    };
    
    class dummy_type {};
    dummy_type init;
    
    template<class T>
    init_type<T> operator << (dummy_type & d, const T & t)
    {
        init_type<T> ret;
        ret.push_back(t);
        return ret;
    }
    
    template<class T>
    init_type<T> & operator << (init_type<T> & initt, const T & t)
    {
        initt.push_back(t);
        return initt;
    }
    
    int main()
    {
        vector<int> v = init<<14<<15;
    }
    So what's the stupid little thing I'm missing?

    Thanks.
    Last edited by CodeMonkey; 03-24-2009 at 09:00 PM. Reason: bolded erroneous line
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> init_type<T> operator << (dummy_type & d, const T & t)
    Would need to return a reference. And then 'ret' would need to be static and cleared explicitly - also making it not thread-safe.

    gg

  3. #3
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    The problem is that init_type is a temporary, so it's going to have to be passed as 'const' (although you'll have to cast it away to push data onto it).
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  4. #4
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    Yes, now I have it working. Thank you.

    Perhaps I could make it thread safe by having
    >> init_type<T> operator << (dummy_type & d, const T & t)
    return a *(new init_type). Then I'd want init_type to destroy itself
    once it has been cast into a container.
    Code:
    delete this;
    comes to mind. Can that ever work?
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Another optimization you could make would be to have the interal vectors swapped, so that the overhead of creating temporaries would be reduced:

    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
    
    template<class T>
    class init_type
    {
      public:
        vector<T> v;
        operator vector<T>()
        {
    	return v;
        }
       //and similarly for list, valarray,etc.
        void push_back(const T & a) { v.push_back(a); }
    };
    
    class dummy_type {};
    dummy_type init;
    
    template<class T>
    init_type<T> operator << (const dummy_type & d, const T & t)
    {
        init_type<T> ret;
        ret.push_back(t);
        return ret;
    }
    
    template<class T>
    init_type<T> operator << (const init_type<T> & initt, const T & t)
    {
        init_type<T> ret;
        ret.v.swap(const_cast<init_type<T> &>(initt).v);
        ret.push_back(t);
        return ret;
    }
    
    int main()
    {
        vector<int> v = init<<14<<15;
    }
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Can that ever work?

    Probably isn't necessary in this case. Just chain a bunch of temporaries together and it should work fine.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  7. #7
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    I see. I like that idea. And this is thread-safe? It looks like it... Thanks, Sebastiani.
    Is there anything unsafe with this way?:
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
    
    template<class T>
    class init_type
    {
        vector<T> v;
      public:
        ~init_type() { cout << "Destroyed!" << endl; }
        operator vector<T>()
        {
            vector<T> ret(v);
    	delete this;
    	return ret;
        }
        void push_back(const T & a) { v.push_back(a); }
    };
    
    class dummy_type {};
    dummy_type init;
    
    template<class T>
    init_type<T> & operator << (dummy_type & d, const T & t)
    {
        init_type<T> *ret = new init_type<T>;
        ret->push_back(t);
        return *ret;
    }
    
    template<class T>
    init_type<T> & operator << (init_type<T> & initt, const T & t)
    {
        initt.push_back(t);
        return initt;
    }
    
    int main()
    {
        vector<int> v = init<<14<<15<<26<<1123<<0<<9;
    }
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  8. #8
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    The only thing I can see wrong with it would be that if the caller never calls operator vector<T>(), then the memory would never be freed. I realize that this is incredibly unlikely, and may not be a concern since that would just defy it's usage anyway. So I guess, practically speaking, it appears safe.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  9. #9
    The larch
    Join Date
    May 2006
    Posts
    3,573
    For putting a bunch of stuff in a container, there's also Boost.Assign

    Code:
    #include <boost/assign.hpp>
    #include <vector>
    
    int main()
    {
        using namespace boost::assign;
        std::vector<int> v;
        v += 14, 15, 26, 1123, 0, 9;
    }
    With less hassle one might also initialize things from a temporary array:

    Code:
    #include <vector>
    
    template <class T, std::size_t N>
    std::size_t size(const T (&) [N])
    {
        return N;
    };
    
    int main()
    {
        int array[] = {14, 15, 26, 1123, 0, 9};
        std::vector<int> v(array, array + size(array));
    }
    C++0x is also promising a new kind of constructors, which should allow you to do something like this:
    Code:
    std::vector<int> v{14, 15, 26, 1123, 0, 9};
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. New stream flushing FAQ candidate?
    By Sebastiani in forum C Programming
    Replies: 9
    Last Post: 07-01-2009, 05:57 PM
  2. Discard wrong data from stream
    By mesmer in forum C Programming
    Replies: 7
    Last Post: 11-16-2008, 02:30 AM
  3. Closing a stream
    By cunnus88 in forum C++ Programming
    Replies: 8
    Last Post: 02-21-2008, 05:15 PM
  4. Help! About text stream and binary stream
    By Antigloss in forum C Programming
    Replies: 1
    Last Post: 09-01-2005, 08:40 AM
  5. Replies: 9
    Last Post: 07-01-2002, 07:50 AM