Opened 10 years ago
Last modified 10 years ago
#1396 new Bugs
wrong result_of invocation around transform_view
Reported by: | 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)
Change History (10)
comment:1 Changed 10 years ago by
Changed 10 years ago by
Attachment: | transform.cpp added |
---|
comment:2 follow-up: 3 Changed 10 years ago by
Here's a more generic identity transform that works for mpl sequences too, FWIW (attached)
Changed 10 years ago by
Attachment: | value_of_transform_view_defect.cpp added |
---|
A defect report of this problem
comment:3 Changed 10 years ago by
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 follow-up: 5 Changed 10 years ago by
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 Changed 10 years ago by
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 follow-up: 8 Changed 10 years ago by
:-) 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
Ooops. Didn't log in. The last two "anonymous" posts are mine (Joel)
comment:8 Changed 10 years ago by
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,
There needs to be a specialization for both Fun(int&) and Fun(int):
or better yet:
This deserves some explanation. Here's why:
Your initial vector is:
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:
then your identity transform is applied calling
hence, the result:
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:
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 :-)