Modify

Opened 10 years ago

Last modified 10 years ago

#1396 new Bugs

wrong result_of invocation around transform_view

Reported by: Shunsuke Sogame <pstade.mb@…> Owned by: Joel de Guzman
Milestone: Boost 1.36.0 Component: fusion
Version: Boost Development Trunk Severity: Problem
Keywords: Cc:

Description

See the following snippet. For some reason, boost::result_of< ::identity(int) > is invoked in as_vector, which means that the argument is rvalue. It should be boost::result_of< ::identity(int &) >.

#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/transform_view.hpp>
#include <boost/fusion/include/vector.hpp>


struct identity
{
    template<class FunCall>
    struct result;

    template<class Fun>
    struct result<Fun(int&)>
    {
        typedef int& type;
    };

    int& operator()(int& i) const
    {
        return i;
    }
};


int main()
{
    typedef boost::fusion::vector<int, int> from_t;
    from_t from;
    boost::fusion::transform_view<from_t, ::identity> v(from, ::identity());

    boost::fusion::as_vector(v); // doesn't compile.
}

Attachments (2)

transform.cpp (1.0 KB) - added by anonymous 10 years ago.
value_of_transform_view_defect.cpp (8.5 KB) - added by Shunsuke Sogame <pstade.mb@…> 10 years ago.
A defect report of this problem

Download all attachments as: .zip

Change History (10)

comment:1 Changed 10 years ago by anonymous

There needs to be a specialization for both Fun(int&) and Fun(int):

    struct identity
    {
        template <typename FunCall>
        struct result;

        template <typename Fun>
        struct result<Fun(int&)>
        {
            typedef int& type;
        };

        template <typename Fun>
        struct result<Fun(int)>
        {
            typedef int& type;
        };

        int& operator()(int& i) const
        {
            return i;
        }
    };

or better yet:

    struct identity
    {
        template <typename FunCall>
        struct result;

        template <typename Fun, typename T>
        struct result<Fun(T)>
        {
            typedef typename boost::add_reference<T>::type type;
        };

        template <typename T>
        T& operator()(T& i) const
        {
            return i;
        }
    };

This deserves some explanation. Here's why:

Your initial vector is:

    vector<int, int>

The underlying types are int and int (hint: not int&). Now, when as_vector tries to compute the resulting vector, it calls value_of to know the exact type of the elements in the input sequence. value_of strips the unnecessary reference that deref may potentially add. It just so happens that what you return is a reference, but that's irrelevant. The important thing is that the input sequence is:

    int, int

then your identity transform is applied calling

     result<Fun(int)>

hence, the result:

    int&, int&

Now...

We haven't started yet. We merely computed the desired result for as_vector. Now the fun begins, the actual conversion starts. The input sequence is walked by an iterator. Here, we *deref* the iterator --which returns an int&. Now, it's obvious why deref returns a reference -- to avoid copies. But then, transform_iterator::deref is also called with this reference parameter, which ultimately calls the identity transform:

     result<Fun(int&)>

Why doesn't STL iterators have this? It does! It's the value_type. Now if only std::vector<T&> is allowed, then the both the value_type and the reference_type would be T&.

Aha! now this is starting to sound like a FAQ :-)

Changed 10 years ago by anonymous

Attachment: transform.cpp added

comment:2 Changed 10 years ago by anonymous

Here's a more generic identity transform that works for mpl sequences too, FWIW (attached)

Changed 10 years ago by Shunsuke Sogame <pstade.mb@…>

A defect report of this problem

comment:3 in reply to:  2 Changed 10 years ago by Shunsuke Sogame <pstade.mb@…>

Replying to anonymous:

Here's a more generic identity transform that works for mpl sequences too, FWIW (attached)

BTW, according to language lawyers, this identity isn't allowed under TR1, because it is not consistent with decltype.

comment:4 Changed 10 years ago by anonymous

IMO, you are wrong. It is correct. The example you have in the boost list thread certainly is ill formed. The example I have here is not.

I've followed the thread (http://tinyurl.com/298abt) but what you missed is the template. The T in Fun(T) is generic and can accommodate references too. This(int) does not.

If you want to avoid dangling references, you can write it as:

struct identity
{
    template<class FunCall>
    struct result;

    template <class Fun, class T>
    struct result<Fun(T&)>
    {
        typedef T& type;
    };
    
    template <class Fun, class T>
    struct result<Fun(T const&)>
    {
        typedef T type;
    };

    template <class T>
    T& operator()(T& val) const
    {
        return val;
    }

    template <class T>
    T operator()(T const& val) const
    {
        return val;
    }
};

comment:5 in reply to:  4 Changed 10 years ago by Shunsuke Sogame <pstade.mb@…>

Replying to anonymous:

IMO, you are wrong. It is correct. The example you have in the boost list thread certainly is ill formed. The example I have here is not.

Ah, right. Unless identity in transform.cpp takes a rvalue, it is ok. Sorry for my confusing.

comment:6 Changed 10 years ago by anonymous

:-) Anyway, I am really convinced that your proposal to add the MetafunctionClass? ValueOf for value_of implementation is the best way to go. It will be added :-)

comment:7 Changed 10 years ago by Joel de Guzman

Ooops. Didn't log in. The last two "anonymous" posts are mine (Joel)

comment:8 in reply to:  6 Changed 10 years ago by Shunsuke Sogame <pstade.mb@…>

Replying to anonymous:

:-) Anyway, I am really convinced that your proposal to add the MetafunctionClass? ValueOf for value_of implementation is the best way to go. It will be added :-)

Please consider it carefully. I'm sometimes wrong :-) Thanks to your patience for my broken english, I have a temporary(cheating) workaround for this problem. Therefore, Fusion professionals have plenty of time to consider.

Regards,

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The owner will remain Joel de Guzman.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.