Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::transform side effect

Tags:

c++

stl

I've implementation of UnaryOperation like this

struct Converter
{
    Converter( std::size_t value ):
        value_( value ), i_( 0 )
    {}
    std::string operator() ( const std::string& word )
    {
        return ( value_ & ( 1 << i_++ ) ) ?
            word:
            std::string( word.size(), ' ' );
    }
    std::size_t value_;
    std::size_t i_;
};

And I use it like

std::vector v;
// initialization of v  
std::transform( v.begin(), v.end(),
                std::back_inserter( result ),
                Converter( data ) );

My question is can I rely on my assumption that algorithm will call my 'Converter operator ()' in the order that 'Converter::i_' will correspond to number of element in 'v'.

Please quote the standard in case I can't rely on the order or put the stl-like solution that avoid possible problem if any.

Thanks.

Edit:

I am aware of "no Side effect" requirements in the standard for the transform algorithm. I can't find what is exactly "side effect" for functors in the same standard.

Maybe there is some good-looking-boost-like solution for this task?

like image 991
Mykola Golubyev Avatar asked Apr 02 '09 07:04

Mykola Golubyev


1 Answers

Qute from standard:

25.2.3 Transform [lib.alg.transform]
Requires:
op and binary_op shall not have any side effects.

Side Effect ( wikipedia definition )

In your case we have next side effect:

Converter c( data );  
c( some_const_value ) != c( some_const_value );

You don't have any guarantees for your algorithms, but I belive that it will works on almost all stl implementations.

Suggested solution
It seems I know one way to do what you need:
use boost::counting_iterator - for iterate over two containers;

it will looks like:

bool bit_enabled( size_t data, unsigned char number )
{
    return ( data & 1 << number ) != 0;
}

std::string select_word( 
                const std::string& word,
                size_t data, 
                size_t number )
{
    return bit_enabled( data, number ) ? word : std::string( ' ', word.length() );
}

const size_t data = 7;
const boost::array< std::string, 3 > vocabulary = { "a", "b", "c" };
std::vector< std::string > result;
std::transform(
    vocabulary.begin(),
    vocabulary.end(),
    boost::counting_iterator< size_t >(0),
    back_inserter( result ),
    boost::bind( &select_word, _1, data, _2 )
);

Also maybe if you will define bit iterator or will use some bit container you will can use boost::zip_iterator for iterate both containers.

EDIT:
Yestarday I found interest article which contain definition of Side Effect by standard.

The Standard defines a side effect as follows: Accessing an object designated by a volatile lvalue, modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment.

EDIT:
I hope it will be latest edit.
I am always tought that "no have side effect" mean:
f(a) should be equal f(a) always. ( f independed from execution environment: memory/cpu/global variables/member variables as in your case etc).
"Not produce side effect" mean - don't changing execution environment.

But in c++ standard we have more low-level defintion for Side effect.

Thing what you do in your example named as Stateful functor.
Standard doesn't say about "Statefull" functors, but also doesn't say about count of copies of your functor - you couldn't use this trick because it is unspecified behavior.

See Standard Library Issues list ( similar issue for predicat ):
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92

like image 192
bayda Avatar answered Sep 28 '22 07:09

bayda