Boost logo

Boost Users :

Subject: [Boost-users] [variant] Custom swap() Not Called
From: Andreas Grosam (agrosam_at_[hidden])
Date: 2011-05-05 15:32:49


Hi,

I'm using a boost::variant whose types have a custom swap() defined. When calling swap() on the variant variable, the custom swap() of the current type will not be called.

The "swapable" class has a member function swap(), and there is also a free function swap() defined in the same namespace (see below).

To illustrate and test the behavior I defined a special "swapable" class:

namespace test {
    
    // This class is for testing purpose only!
    class swapable {
    public:
        swapable() : swapped_(0) {}
        swapable(const swapable& other)
        : swapped_(0)
        {
        }
        
        ~swapable() { }
        
        int swapped() const { return swapped_; }
        
        void swap(swapable& other) {
            ++swapped_; ++other.swapped_;
        }
        
        swapable& operator= (const swapable& other) {
            return *this;
        }
        
    private:
        int swapped_;
    };
    
    
    void swap(swapable& lhv, swapable& rhv) {
        lhv.swap(rhv);
    }
}

The calling context looks as follows:

void test()
{
    typedef boost::variant< test::swapable > variant_t;

    variant_t v0( (test::swapable()) );
    variant_t v1( (test::swapable()) );
    
    swap(v0, v1);
    
    bool swapCalled = boost::get<test::swapable>(v0).swapped() == 1 and boost::get<test::swapable>(v1).swapped() == 1;
    std::cout << "boost::variant swap test: " << (swapCalled ? "PASSED":"FAILED" ) << std::endl;
}

So, assuming Koenig lookup works (which in fact does work for the compilers I'm using) calling swap() for the varaint variable should finally call the custom swap(), but it doesn't.

Looking deeper into the sources, the culprit seem to be a workaround declaration in file move.hpp (please see below).
Note: I'm using gcc, clang and apple's versions of clang. For these compilers __GNUC__ is defined as 4, and in the current config setup BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(2)) evaluates to true.

So, when the workaround has been selected, it seems this effectively prevents Koenig lookup which then uses a std::swap like mechanism.

Well, now since the compilers I'm using do not have issues with argument-dependent name lookup, how can I fix this - respectively, what is the preferred way to make this work (config setting, maybe)?

Note: for testing purposes, I defined BOOST_STRICT_CONFIG 1 (which disables all workarounds) - and this test ran fine.

As a side note: I only figured that there is an issue with custom swap() through making performance test - as they ran as slow as a copy. As far as I can see, the boost::variant test suite does not cover such cases. The types which the variant shall hold are copy-expensive - but they are very fast when swap is used (or rvalue reference is enabled some times for boost::variant).

Thanks in advance for tips!

Regards
Andreas

//////////////////////////////////////////////////////////////////////////
// function template move_swap
//
// Swaps using Koenig lookup but falls back to move-swap for primitive
// types and on non-conforming compilers.
//

#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) \
 || BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(2))

// [Indicate that move_swap by overload is disabled...]
#define BOOST_NO_MOVE_SWAP_BY_OVERLOAD

// [...and provide straight swap-by-move implementation:]
template <typename T>
inline void move_swap(T& lhs, T& rhs)
{
    T tmp( boost::detail::variant::move(lhs) );
    lhs = boost::detail::variant::move(rhs);
    rhs = boost::detail::variant::move(tmp);
}

#else// !workaround

namespace detail { namespace move_swap {

template <typename T>
inline void swap(T& lhs, T& rhs)
{
    T tmp( boost::detail::variant::move(lhs) );
    lhs = boost::detail::variant::move(rhs);
    rhs = boost::detail::variant::move(tmp);
}

}} // namespace detail::move_swap


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net