Thread: What should it say on the label?

  1. #1
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108

    What should it say on the label?

    [Edit]
    Be fairly warned, I could not decide where to put this post; it is a programming question with C++ examples, but the question isn't about the code.
    [/Edit]

    ;_;

    So, being that I am a guy who loves the iterator pattern, "commit or rollback", and "ad-hoc" transformations I have a large number of tools designed to decorate iterators to fit my approach to solving problems.

    (You can look below for an example.)

    The thing is, I have several dozen of these decorations, and for now they have really messy names with lots of near/explicit collisions--like `Iterators::TransformResult', `Iterators::TransformSequence', and `Iterators::TransformSequenceResult'.

    The naming isn't as bad for the interface, just various overloads of `Transform' for example, but the template classes to be specialized must exist.

    I know this seems like a small thing to many of you, but I've officially reached the point where I can't even keep track of things so anyone else trying to debug code has no chance of following the errors.

    Yeah, I could further separate the various flavors into "namespaces" or "tagging", but from an outside perspective `IteratorSomethingNameSpecialty' is not practically different from `Iterator::SomethingNameSpecialty' or `Iterator::Something<NameSpecialty>'.

    Help!?

    Soma

    For example, instead of augmenting the sequence with the "STL":

    Code:
    /* C++11 */
    int main
    (
        int argc
      , char ** argv
    )
    {
        vector<string> sSource(argv + 1, argv + argc);
        vector<string> sDestination;
        transform(sSource.begin(), sSource.end(), back_inserter(sDestination), [] (const string & f) {return f + '\n';});
        copy(sDestination.begin(), sDestination.end(), ostream_iterator<string>(cout, ""));
    }
    each element within the collection would be augmented:

    Code:
    int main
    (
        int argc
      , char ** argv
    )
    {
        vector<string> sSource(argv + 1, argv + argc);
        auto sDestination = Whatever(sSource, [] (const string & f) {return f + '\n';});
        copy(sDestination.begin(), sDestination.end(), ostream_iterator<string>(cout, ""));
    }
    where the iterator for `sDestination' (whatever type it may be) is doing something like:

    Code:
    std::string operator * ()
    {
        return mTransform(mSelf);
    }
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    DecoratingContainer? TransformingContainer? ManipulativeContainer?

    Personally, I'd do it using std::transform() rather than introducing another container type with special iterators. Particularly as sDestination has a strong resemblance to a vector<string>, it's just that each string has a newline appended.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    [Edit]
    Personally, I'd do it using std::transform() rather than introducing another container type with special iterators.
    ;_;

    *sigh*

    I am a complete and total idiot.

    If I would have thought about it, I would have explained everything else in this post with a few lines.

    Code:
    transform(sSource.begin(), sSource.end(), back_inserter(sDestination), [] (const string & f) {return f + '\n';});
    You said you'd do it with such a `transform', right?

    Okay. Well, in that example, the `std::back_inserter' function is wrapping the destination container not with a new container but with a fancy iterator.

    Code:
    copy(sDestination.rbegin(), sDestination.rend(), ostream_iterator<string>(cout, ""));
    You've probably also used something like the "reverse iterators" from this example.

    In that example, the `rbegin' method wraps the normal iterator--from `begin'--from the source with the `reverse_iterator' constructor.

    My iterators have the same underlying mechanisms you already use in the way you already use them. The only "new"/"special" aspect of the iterators is that the mechanism is programmable (arbitrary transforms) rather than fixed (use `--' instead of `++').

    Feel free to read on, though this has said much as the rest.
    [/Edit]

    DecoratingContainer? TransformingContainer? ManipulativeContainer?
    O_o

    I apparently did a poor job in explaining.

    The result of such decorations apply "in place" to sequences; these are not containers by any stretch of the imagination.

    Within the second example: No new container is created. No such container exists in the code. No new storage is used. No sequence actually is sampled in the creation of `sDestination'.

    I have included an example so that you might understand "what happens behind the scenes". Keep in mind, the example is flawed and too simplified to actually be useful, but the general idea of transforming the result of sampling a sequence while sampling a sequence is present.

    [Edit]
    The relevant lines are near the bottom of the code in `main'.

    Code:
    auto sSelected = Selector(sSource, SelectOddIdentifier);
    auto sTransformed = Transformer(sSelected, TransformName);
    auto sAccessed = Access<string>(sTransformed, AccessName);
    These variables (`sSelected', `sTransformed', and `sAccessed') are not instances of `std::vector<???>'; they are instances of `SSequenceWrapper'. They exist only to provide a canonical means of getting the decorated iterators, but you could, if so desired, directly create the decorated iterators from anything that itself support iteration.

    Many forms of the iterators exist which change the mechanism by which the actual and only storage--`sSource' a `std::vector<SSimple>' object--is sequenced and the results of processing the elements belonging to that sequence. Crucially, no new container, iterator category, or method of iteration exists.
    [/Edit]

    [Edit]
    The code from the example is very unsophisticated.

    With the corrected form, the decoration is may be chained:

    Code:
    vector<SSimple> sDestination(Collect<vector<SSimple>>(vectorAccess<string>(Transformer(Selector(sSource, SelectOddIdentifier), TransformName), AccessName)));
    The selection, transformation, and member access is born of iteration over the sequence. Any client code operating on a pair of iterators may use the decorated iterators as is normal for that category of iterators. The example of chains is hideous, and I would not write in that way in any event, but I wanted to present it to show the rationale behind such methods.

    Simply put, it enhances patterns built around treating a container as being a collection of items instead of a container.
    [/Edit]

    Personally, I'd do it using std::transform() rather than introducing another container type with special iterators.
    Well, that is your prerogative regardless of the availability of such decorations.

    I'd also imagine that you don't do "commit or rollback" as I do, and that too is your privilege, but I am willing to "pay the price" for duplicating data/recording transactions/similar so that errors do not harm existing data so that is precisely what I do.

    Particularly as sDestination has a strong resemblance to a vector<string>, it's just that each string has a newline appended.
    The `sDestination' from the second example has no resemblance to a `std::vector<string>'; the relevant template classes have only six/seven operations.

    Well, actually, because repeating the boilerplate would be a waste of time, the same template class representing the decorated sequence is returned for all decorations with only the iterators being different--a template parameter.

    Soma

    Code:
    #include <iostream>
    #include <iterator>
    #include <string>
    #include <vector>
    
    /**********************************************************************************************/
    
    template
    <
        typename FContainer
      , typename FIterator
      , typename FMechanism
    >
    struct SSequenceWrapper
    {
        typedef FIterator iterator;
        SSequenceWrapper
        (
            FContainer * fContainer
          , FMechanism fMechanism
        ):
            mContainer(fContainer)
          , mMechanism(fMechanism)
        {
        }
        FIterator begin()
        {
            return(FIterator(mContainer->begin(), mContainer->end(), mMechanism));
        }
        FIterator end()
        {
            return(FIterator(mContainer->end(), mContainer->end(), mMechanism));
        }
        FContainer * mContainer;
        FMechanism mMechanism;
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    struct SIteratorBase:
        public std::iterator<std::input_iterator_tag, FResult>
    {
        SIteratorBase
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            mOrigin(fOrigin)
          , mTerminus(fTerminus)
          , mMechanism(fMechanism)
        {
        }
        FIterator mOrigin;
        FIterator mTerminus;
        FMechanism mMechanism;
    };
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    bool operator <
    (
        const SIteratorBase<FIterator, FMechanism, FResult> & fLHS
      , const SIteratorBase<FIterator, FMechanism, FResult> & fRHS
    )
    {
        return fLHS.mOrigin < fRHS.mOrigin;
    }
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    bool operator !=
    (
        const SIteratorBase<FIterator, FMechanism, FResult> & fLHS
      , const SIteratorBase<FIterator, FMechanism, FResult> & fRHS
    )
    {
        return fLHS.mOrigin != fRHS.mOrigin;
    }
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    size_t operator -
    (
        const SIteratorBase<FIterator, FMechanism, FResult> & fLHS
      , const SIteratorBase<FIterator, FMechanism, FResult> & fRHS
    )
    {
        return fLHS.mOrigin - fRHS.mOrigin;
    }
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FTarget
    >
    struct SIteratorAccess:
        public SIteratorBase<FIterator, FMechanism, FTarget>
    {
        SIteratorAccess
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            SIteratorBase<FIterator, FMechanism, FTarget>(fOrigin, fTerminus, fMechanism)
        {
        }
        FTarget operator * ()
        {
            return(this->mMechanism(*this->mOrigin));
        }
        SIteratorAccess & operator ++ ()
        {
            ++this->mOrigin;
            return(*this);
        }
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
    >
    struct SIteratorSelect:
        public SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>
    {
        typedef std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type> iterator_traits;
        typedef typename iterator_traits::value_type value_type;
        SIteratorSelect
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>(fOrigin, fTerminus, fMechanism)
        {
            while((fOrigin < fTerminus) && !fMechanism(*fOrigin))
            {
                ++fOrigin;
            }
            this->mOrigin = fOrigin;
        }
        value_type operator * ()
        {
            return(*this->mOrigin);
        }
        SIteratorSelect & operator ++ ()
        {
            FIterator sOrigin(this->mOrigin);
            FIterator sTerminus(this->mTerminus);
            ++sOrigin;
            while((sOrigin < sTerminus) && !this->mMechanism(*sOrigin))
            {
                ++sOrigin;
            }
            this->mOrigin = sOrigin;
            return(*this);
        }
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
    >
    struct SIteratorTransform:
        public SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>
    {
        typedef std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type> iterator_traits;
        typedef typename iterator_traits::value_type value_type;
        SIteratorTransform
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>(fOrigin, fTerminus, fMechanism)
        {
        }
        value_type operator * ()
        {
            return(this->mMechanism(*this->mOrigin));
        }
        SIteratorTransform & operator ++ ()
        {
            ++this->mOrigin;
            return(*this);
        }
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FTarget
      , typename FContainer
      , typename FMechanism
    >
    SSequenceWrapper<FContainer, SIteratorAccess<typename FContainer::iterator, FMechanism, FTarget>, FMechanism> Access
    (
        FContainer & fContainer
      , FMechanism fMechanism
    )
    {
        return(SSequenceWrapper<FContainer, SIteratorAccess<typename FContainer::iterator, FMechanism, FTarget>, FMechanism>(&fContainer, fMechanism));
    }
    
    template
    <
        typename FContainer
      , typename FMechanism
    >
    SSequenceWrapper<FContainer, SIteratorSelect<typename FContainer::iterator, FMechanism>, FMechanism> Selector
    (
        FContainer & fContainer
      , FMechanism fMechanism
    )
    {
        return(SSequenceWrapper<FContainer, SIteratorSelect<typename FContainer::iterator, FMechanism>, FMechanism>(&fContainer, fMechanism));
    }
    
    template
    <
        typename FContainer
      , typename FMechanism
    >
    SSequenceWrapper<FContainer, SIteratorTransform<typename FContainer::iterator, FMechanism>, FMechanism> Transformer
    (
        FContainer & fContainer
      , FMechanism fMechanism
    )
    {
        return(SSequenceWrapper<FContainer, SIteratorTransform<typename FContainer::iterator, FMechanism>, FMechanism>(&fContainer, fMechanism));
    }
    
    /**********************************************************************************************/
    
    struct SSimple
    {
        SSimple
        (
            unsigned int fIdentifier
          , const std::string & fName
        ):
            mIdentifier(fIdentifier)
          , mName(fName)
        {
        }
        unsigned int mIdentifier;
        std::string mName;
    };
    
    std::ostream & operator <<
    (
        std::ostream & fLHS
      , const SSimple & fRHS
    )
    {
        fLHS << "SSimple(" << fRHS.mIdentifier << ", \"" << fRHS.mName << "\");";
    }
    
    /**********************************************************************************************/
    
    std::string AccessName
    (
        const SSimple & f
    )
    {
        return(f.mName);
    }
    
    bool SelectOddIdentifier
    (
        const SSimple & f
    )
    {
        return(f.mIdentifier % 2);
    }
    
    SSimple TransformName
    (
        const SSimple & f
    )
    {
        return(SSimple(f.mIdentifier, '!' + f.mName));
    }
    
    /**********************************************************************************************/
    
    template
    <
        typename FContainer
      , typename FIterator
    >
    void Copy
    (
        FContainer & fContainer
      , FIterator fDestination
    )
    {
        copy(fContainer.begin(), fContainer.end(), fDestination);
    }
    
    int main
    (
        int argc
      , char ** argv
    )
    {
        using namespace std;
        vector<SSimple> sSource;
        sSource.push_back(SSimple(1, "Test1"));
        sSource.push_back(SSimple(2, "Test2"));
        sSource.push_back(SSimple(3, "Test3"));
        sSource.push_back(SSimple(4, "Test4"));
        sSource.push_back(SSimple(5, "Test5"));
    /**********************************************************************************************/
    /* These lines do not create a new collection.                                                */
    /**********************************************************************************************/
        auto sSelected = Selector(sSource, SelectOddIdentifier);
        auto sTransformed = Transformer(sSelected, TransformName);
        auto sAccessed = Access<string>(sTransformed, AccessName);
    /**********************************************************************************************/
    /* These lines only decorate while the elements are being iterated over for sampling.         */
    /**********************************************************************************************/
        Copy(sSource, ostream_iterator<SSimple>(cout, "\n"));
        cout << '\n';
        Copy(sSelected, ostream_iterator<SSimple>(cout, "\n"));
        cout << '\n';
        Copy(sTransformed, ostream_iterator<SSimple>(cout, "\n"));
        cout << '\n';
        Copy(sAccessed, ostream_iterator<string>(cout, "\n"));
    }
    Last edited by phantomotap; 01-09-2014 at 12:17 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  4. #4
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by phantomotap View Post
    Code:
    #include <iostream>
    #include <iterator>
    #include <string>
    #include <vector>
    
    /**********************************************************************************************/
    
    template
    <
        typename FContainer
      , typename FIterator
      , typename FMechanism
    >
    struct SSequenceWrapper
    {
        typedef FIterator iterator;
        SSequenceWrapper
        (
            FContainer * fContainer
          , FMechanism fMechanism
        ):
            mContainer(fContainer)
          , mMechanism(fMechanism)
        {
        }
        FIterator begin()
        {
            return(FIterator(mContainer->begin(), mContainer->end(), mMechanism));
        }
        FIterator end()
        {
            return(FIterator(mContainer->end(), mContainer->end(), mMechanism));
        }
        FContainer * mContainer;
        FMechanism mMechanism;
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    struct SIteratorBase:
        public std::iterator<std::input_iterator_tag, FResult>
    {
        SIteratorBase
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            mOrigin(fOrigin)
          , mTerminus(fTerminus)
          , mMechanism(fMechanism)
        {
        }
        FIterator mOrigin;
        FIterator mTerminus;
        FMechanism mMechanism;
    };
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    bool operator <
    (
        const SIteratorBase<FIterator, FMechanism, FResult> & fLHS
      , const SIteratorBase<FIterator, FMechanism, FResult> & fRHS
    )
    {
        return fLHS.mOrigin < fRHS.mOrigin;
    }
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    bool operator !=
    (
        const SIteratorBase<FIterator, FMechanism, FResult> & fLHS
      , const SIteratorBase<FIterator, FMechanism, FResult> & fRHS
    )
    {
        return fLHS.mOrigin != fRHS.mOrigin;
    }
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FResult
    >
    size_t operator -
    (
        const SIteratorBase<FIterator, FMechanism, FResult> & fLHS
      , const SIteratorBase<FIterator, FMechanism, FResult> & fRHS
    )
    {
        return fLHS.mOrigin - fRHS.mOrigin;
    }
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
      , typename FTarget
    >
    struct SIteratorAccess:
        public SIteratorBase<FIterator, FMechanism, FTarget>
    {
        SIteratorAccess
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            SIteratorBase<FIterator, FMechanism, FTarget>(fOrigin, fTerminus, fMechanism)
        {
        }
        FTarget operator * ()
        {
            return(this->mMechanism(*this->mOrigin));
        }
        SIteratorAccess & operator ++ ()
        {
            ++this->mOrigin;
            return(*this);
        }
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
    >
    struct SIteratorSelect:
        public SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>
    {
        typedef std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type> iterator_traits;
        typedef typename iterator_traits::value_type value_type;
        SIteratorSelect
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>(fOrigin, fTerminus, fMechanism)
        {
            while((fOrigin < fTerminus) && !fMechanism(*fOrigin))
            {
                ++fOrigin;
            }
            this->mOrigin = fOrigin;
        }
        value_type operator * ()
        {
            return(*this->mOrigin);
        }
        SIteratorSelect & operator ++ ()
        {
            FIterator sOrigin(this->mOrigin);
            FIterator sTerminus(this->mTerminus);
            ++sOrigin;
            while((sOrigin < sTerminus) && !this->mMechanism(*sOrigin))
            {
                ++sOrigin;
            }
            this->mOrigin = sOrigin;
            return(*this);
        }
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FIterator
      , typename FMechanism
    >
    struct SIteratorTransform:
        public SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>
    {
        typedef std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type> iterator_traits;
        typedef typename iterator_traits::value_type value_type;
        SIteratorTransform
        (
            FIterator fOrigin
          , FIterator fTerminus
          , FMechanism fMechanism
        ):
            SIteratorBase<FIterator, FMechanism, typename std::iterator<typename std::iterator_traits<FIterator>::iterator_category, typename std::iterator_traits<FIterator>::value_type>::value_type>(fOrigin, fTerminus, fMechanism)
        {
        }
        value_type operator * ()
        {
            return(this->mMechanism(*this->mOrigin));
        }
        SIteratorTransform & operator ++ ()
        {
            ++this->mOrigin;
            return(*this);
        }
    };
    
    /**********************************************************************************************/
    
    template
    <
        typename FTarget
      , typename FContainer
      , typename FMechanism
    >
    SSequenceWrapper<FContainer, SIteratorAccess<typename FContainer::iterator, FMechanism, FTarget>, FMechanism> Access
    (
        FContainer & fContainer
      , FMechanism fMechanism
    )
    {
        return(SSequenceWrapper<FContainer, SIteratorAccess<typename FContainer::iterator, FMechanism, FTarget>, FMechanism>(&fContainer, fMechanism));
    }
    
    template
    <
        typename FContainer
      , typename FMechanism
    >
    SSequenceWrapper<FContainer, SIteratorSelect<typename FContainer::iterator, FMechanism>, FMechanism> Selector
    (
        FContainer & fContainer
      , FMechanism fMechanism
    )
    {
        return(SSequenceWrapper<FContainer, SIteratorSelect<typename FContainer::iterator, FMechanism>, FMechanism>(&fContainer, fMechanism));
    }
    
    template
    <
        typename FContainer
      , typename FMechanism
    >
    SSequenceWrapper<FContainer, SIteratorTransform<typename FContainer::iterator, FMechanism>, FMechanism> Transformer
    (
        FContainer & fContainer
      , FMechanism fMechanism
    )
    {
        return(SSequenceWrapper<FContainer, SIteratorTransform<typename FContainer::iterator, FMechanism>, FMechanism>(&fContainer, fMechanism));
    }
    
    /**********************************************************************************************/
    
    struct SSimple
    {
        SSimple
        (
            unsigned int fIdentifier
          , const std::string & fName
        ):
            mIdentifier(fIdentifier)
          , mName(fName)
        {
        }
        unsigned int mIdentifier;
        std::string mName;
    };
    
    std::ostream & operator <<
    (
        std::ostream & fLHS
      , const SSimple & fRHS
    )
    {
        fLHS << "SSimple(" << fRHS.mIdentifier << ", \"" << fRHS.mName << "\");";
    }
    
    /**********************************************************************************************/
    
    std::string AccessName
    (
        const SSimple & f
    )
    {
        return(f.mName);
    }
    
    bool SelectOddIdentifier
    (
        const SSimple & f
    )
    {
        return(f.mIdentifier % 2);
    }
    
    SSimple TransformName
    (
        const SSimple & f
    )
    {
        return(SSimple(f.mIdentifier, '!' + f.mName));
    }
    
    /**********************************************************************************************/
    
    template
    <
        typename FContainer
      , typename FIterator
    >
    void Copy
    (
        FContainer & fContainer
      , FIterator fDestination
    )
    {
        copy(fContainer.begin(), fContainer.end(), fDestination);
    }
    
    int main
    (
        int argc
      , char ** argv
    )
    {
        using namespace std;
        vector<SSimple> sSource;
        sSource.push_back(SSimple(1, "Test1"));
        sSource.push_back(SSimple(2, "Test2"));
        sSource.push_back(SSimple(3, "Test3"));
        sSource.push_back(SSimple(4, "Test4"));
        sSource.push_back(SSimple(5, "Test5"));
    /**********************************************************************************************/
    /* These lines do not create a new collection.                                                */
    /**********************************************************************************************/
        auto sSelected = Selector(sSource, SelectOddIdentifier);
        auto sTransformed = Transformer(sSelected, TransformName);
        auto sAccessed = Access<string>(sTransformed, AccessName);
    /**********************************************************************************************/
    /* These lines only decorate while the elements are being iterated over for sampling.         */
    /**********************************************************************************************/
        Copy(sSource, ostream_iterator<SSimple>(cout, "\n"));
        cout << '\n';
        Copy(sSelected, ostream_iterator<SSimple>(cout, "\n"));
        cout << '\n';
        Copy(sTransformed, ostream_iterator<SSimple>(cout, "\n"));
        cout << '\n';
        Copy(sAccessed, ostream_iterator<string>(cout, "\n"));
    }
    C++ is the new Java.

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    C++ is the new Java.
    O_o

    A little history for you: the ideas that became "Java Collections Framework" were born from work on the "STL" by Stepanov and Lee which in turn was based on "OOP" patterns--despite assertions to the contrary by Stepanov--from texts then a decade old.

    The ideas here are literally ~30 years old predating Java by a lot.

    Perhaps you should be saying "C++ is the new Smalltalk.".

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  6. #6
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    ^_^

    Oh, sorry.

    Thanks for commenting, grumpy.

    Honestly, I don't like your suggestions (The iterators aren't containers so such names would not impart "Does what it says on the label.".) much, but the suggestions reminded me of "Boost" so I've been taking a look at how they handled implementation naming, and maybe that will yield some appropriate strategy.

    [Edit]
    Also, for anyone who doesn't want to parse my example code, you would be better served reading the examples/documentation from "Boost" which has very similar features.

    The Boost.Iterator Library Boost - 1.55.0
    [/Edit]

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by phantomotap View Post
    [Edit]

    ;_;

    *sigh*

    I am a complete and total idiot.

    If I would have thought about it, I would have explained everything else in this post with a few lines.

    Code:
    transform(sSource.begin(), sSource.end(), back_inserter(sDestination), [] (const string & f) {return f + '\n';});
    You said you'd do it with such a `transform', right?

    Okay. Well, in that example, the `std::back_inserter' function is wrapping the destination container not with a new container but with a fancy iterator.

    Code:
    copy(sDestination.rbegin(), sDestination.rend(), ostream_iterator<string>(cout, ""));
    You've probably also used something like the "reverse iterators" from this example.

    In that example, the `rbegin' method wraps the normal iterator--from `begin'--from the source with the `reverse_iterator' constructor.

    My iterators have the same underlying mechanisms you already use in the way you already use them. The only "new"/"special" aspect of the iterators is that the mechanism is programmable (arbitrary transforms) rather than fixed (use `--' instead of `++').

    Feel free to read on, though this has said much as the rest.
    [/Edit]
    I'm not sure if all recommendations are equal in this situation but I think I have a few ideas.

    On one hand I kinda want to be a jerk and call it a ProgrammableTransformIterator simply because you used those terms.

    For stuff that you want a client to ignore though, you can just shove it in a namespace called detail and someone stupid, like me, is smart enough to ignore it. Boost seems to do exactly this.

    (arbitrary transforms) rather than fixed (use `--' instead of `++').
    Part of me wonders if you need names for this stuff too. It sounds like your fancy iterator can go in arbitrary directions, or there might not be a 'direction' per se in use cases for what you are making, and in that case, I would say that the transformation, no matter what kind it is, takes a "step".

  8. #8
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by phantomotap View Post
    A little history for you: the ideas that became "Java Collections Framework" were born from work on the "STL" by Stepanov and Lee which in turn was based on "OOP" patterns--despite assertions to the contrary by Stepanov--from texts then a decade old.
    Ok.
    I'm not referring to OOP or collections, per se. But to solving of small problems with complex and extremely verbose solutions.

    Quote Originally Posted by phantomotap View Post
    Perhaps you should be saying "C++ is the new Smalltalk.".
    lol

  9. #9
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    For stuff that you want a client to ignore though, you can just shove it in a namespace called detail and someone stupid, like me, is smart enough to ignore it.
    O_o

    Well, the thing is, you are only thinking as a client with perfect code.

    I know you've seen the sort of errors produced by C++ compilers when the "STL" is involved.

    If not though, try throwing a constant container at some code incorrectly using a mutable reverse iterator: the list of every potential overload now comes with a recursive listing of the errors occurring during decoration--the problems with expanding each template with a template of the wrong "constness".

    I'm asking specifically for suggestions because you can't shuffle the identities of the implementations to the side; good compilers will list the origin of problems but also the point of failure.

    Well, you could; I'm not going to do that. I am trying to avoid generic, ridiculously overloaded terms.

    Sure, seeing only a few instances of `ProgrammableTransformIterator' isn't a significant problem, but now imagine getting dozens/hundreds of pages of "errors"/"hints" recursively referencing where in the chain of responsibilities a method is called or a parameter passed--expanding another template--each talking about `ProgrammableTransformIterator', `ProgrammableAccessIterator', and `ProgrammableSelectorIterator'!

    So, yeah, I'm looking for names/strategies for naming that might help clarify the overwhelming errors presented to clients when things go wrong not keeping the names from trampling over the implementer (me).

    But to solving of small problems with complex and extremely verbose solutions.
    [Edit]
    At first, I thought you were just trolling and dismissed you out of hand because of your behavior in some other threads, but then I considered that you may have been honestly criticizing the example by invoking Java not in the "Oh. My. God. OOPS." way as it seemed but in the "Enterprise Java Beans" way which is valid if misplaced.

    So, that said, if you or any other were able to see the dismissive post before the deletion/edit I apologize.

    Obviously, I don't agree with the criticism, but to be fair to what I also see as a complete waste in everything that is "Java Enterprise Beans", I acknowledge: here is a modest, if wordy, exploration into the reasons behind the ideas referenced in this thread.
    [/Edit]

    You have tripped over the example code because it seems as if pointlessly complex. (The code is actually massively simplified. The code necessary to do proper selection over the return value of transforms is by itself larger and more complex than the code I posted. So, in that respect, the code is even worse than what you imagine.) However, that doesn't actually matter in the least because the code does not really exhibit the "solving of small problems". The code solves entire categories of problems with a familiar interface named with familiar labels.

    If you'll allow me to explain, the real code considers navigation/transformation separately regardless of the collections and elements involved.

    In other words, the code is massive, but the code works with any element types, container types, navigation adjustments, and transformations that conform to the expected interface.

    So, for example, let us assume you have made a real class that you need to store in a container. Furthermore, let us assume that the real class is expensive to manipulate in any form--compare/copy/whatever. Finally, let us set our task as finding certain elements, manipulating them, and storing the result within a second container.

    You might legitimately argue that the simpler process is superior:

    Code:
    for(int c(0); c < SourceSize; ++c)
    {
        if(Condition(Source[c]))
        {
            Destination.push_back(Manipulate(Source[c]));
        }
    }
    For the sake of argument, grant me that both `Condition' and `Manipulate' are non-trivial. (Possibly, this is some "business logic" pulled from configuration files.) So, these aren't really things you would or could code directly within the loop above. With this in mind, both `Condition' and `Manipulate' must exist.

    Consider please that the simpler process is also fixed for entirely arbitrary reasons. The imagined mechanism as presented in the code fragment is really the same regardless of the "values" represented by `Source', `Destination', `Condition', and `Manipulate'. In the real world, the imagined "values" are probably not going to be fixed so why should the implementation be fixed? With that in mind--the expectation of a similar fragment with different labels inserted for `Source', `Destination', `Condition', and `Manipulate'--would you not create a function so that you might programmatically feed the same fragment with different "values"? It is very likely that you will see the need for the function `Loop' at some point so that instead of manually creating a destination container and coding the fragment you may simply harvest the results of the mechanism.

    Code:
    Whatever Destination(Loop(Source, Condition, Manipulate));
    With C++11 and a good compiler, you are losing nothing of performance, but you gain as a coder: the label for `Loop' and the "values" may be written to impart more information in a concise form.

    Code:
    std::vector<Account> Overdrawn(Audit(AllAccounts, HasNegativeBalance, SetOverdrawnFlag));
    As far as I am concerned, the `Audit' form is vastly superior from the maintainers point of view while still having the obvious flaw of "doing two things for no good reason".

    Code:
    std::vector<Account> Overdrawn(Audit(Query(AllAccounts, HasNegativeBalance), SetOverdrawnFlag));
    I'd argue that this updated line is no less concise yet even more descriptive.

    [Edit]
    The `Collect' template function is something I use in a lot of my code dealing with iterator pairs.

    The call to collect says "Collect<as this thing>(this stuff)" and essentially just calls the relevant constructor with `begin()'/`end()'.
    [/Edit]

    Code:
    auto Overdrawn = Query(AllAccounts, HasNegativeBalance);
    std::vector<Account> Audited(Collect<std::vector<Account>>(Audit(Overdrawn , SetOverdrawnFlag)));
    I'd argue that this form with multiple lines is almost perfect. (Just to be clear, I don't think C++11 can hit "perfect" in this context.) You may still argue for the "simpler process", but I appreciate the concise, highly informative nature of those two lines more than I can really express.

    Let me offer one final bit of code:

    Code:
    auto Overdrawn = Selector(AllAccounts, HasNegativeBalance);
    std::vector<Account> Audited(Collect<std::vector<Account>>(Transformer(Overdrawn , SetOverdrawnFlag)));
    The tools I've referenced here are the same exact thing as `Audit' and `Query' presented as simple generics (That is, I'm offering overloaded/templated/polymorphic tools with names somewhat less descriptive for the sake of having that jargon available.) over "finer grained" facilities with an interface every good C++ programmer already knows: iterators.

    Soma
    Last edited by phantomotap; 01-09-2014 at 03:41 AM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by phantomotap View Post
    Honestly, I don't like your suggestions (The iterators aren't containers so such names would not impart "Does what it says on the label.".) much, but the suggestions reminded me of "Boost" so I've been taking a look at how they handled implementation naming, and maybe that will yield some appropriate strategy.
    That's okay. I didn't have particularly high liking for my suggestions either. They're what came to my mind looking at your example (which I recognised may not capture all your intent).

    Where my thoughts cam from though is that your "Whatever" was something that supplies a begin() and and end() - which is part of the standard container interface. So I thought of your "Whatever" as having more in common with a container than an iterator.

    On your subsequent comments with back_inserter ..... back_inserter is generally categorised as an interface adapter
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  11. #11
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Where my thoughts cam from though is that your "Whatever" was something that supplies a begin() and and end() - which is part of the standard container interface. So I thought of your "Whatever" as having more in common with a container than an iterator.
    O_o

    Yes, you are right.

    Having considered that possibility, my original post presents`Whatever' as being more of a constructor than an interface over an adapter.

    That was sloppy, but honestly, I was afraid to present too much of the situation for fear no one would respond to the post. I guess I just undershot.

    On your subsequent comments with back_inserter ..... back_inserter is generally categorised as an interface adapter
    I've heard that suggestion from others, and the jargon works, but that really doesn't get me anywhere.

    The label `back_insert_adapter' really does nothing different than `back_insert_iterator'.

    >_<

    This is so frustrating. Everything that might be reasonably descriptive is so ridiculously overloaded that it loses all meaning in this context.

    *sigh*

    Are the folks at home wondering if this is really an issue?

    YES!

    I've been coding for over twenty years. Coding is a huge part of my life. I can't help but take pride in it, but things like this that can't really be solved with the science is terribly frustrating to me.

    *shrug*

    I admittedly don't art as well as I science, but I'm convinced that poetry wouldn't help much anyway.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  12. #12
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    ^_^

    Also, thanks to everyone posting.

    I've gotten a way better response here than elsewhere, and that alone is encouraging.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  13. #13
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Lol this topic makes me feel bad at C++ T_T

    And poetry always helps! There are only a couple of poems that I actually enjoy (the Divine Comedy and Paradise Lost) though poetic things don't always have a place in programming. "What's your variable name there?" I felt like NightPain was a good way to describe the orientation of tetrahedra.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. is there a way if label = ? do this
    By mxadam in forum C# Programming
    Replies: 2
    Last Post: 07-15-2010, 09:22 PM
  2. Label Box
    By Coding in forum Windows Programming
    Replies: 6
    Last Post: 02-22-2008, 04:28 PM
  3. Label within a label?
    By Manaxter in forum C# Programming
    Replies: 0
    Last Post: 11-04-2006, 09:49 AM
  4. How To Label!!!HELP!!!
    By himanch in forum C++ Programming
    Replies: 12
    Last Post: 02-06-2005, 07:25 AM
  5. STATIC text label or LABEL in Windows APP - NO MFC!
    By triste in forum Windows Programming
    Replies: 5
    Last Post: 10-25-2004, 11:14 PM