Opened 8 years ago

Closed 4 years ago

#10133 closed Bugs (fixed)

boost 1.55 breaks fusion map arrays

Reported by: steven.seeger@… Owned by: Joel de Guzman
Milestone: Boost 1.68.0 Component: fusion
Version: Boost 1.55.0 Severity: Regression
Keywords: Cc:

Description

The attached code compiles and runs on 1.53 with the attached output. It fails to build on 1.55 with the attached error. (gcc 4.8.2)

build with:

g++ fusion_map.cpp -o fusion_map -std=c++11

Attachments (3)

fusion_map.cpp (843 bytes ) - added by anonymous 8 years ago.
fusion_map_1.53 (27 bytes ) - added by anonymous 8 years ago.
fusion_map.error.1.55 (7.5 KB ) - added by anonymous 8 years ago.

Download all attachments as: .zip

Change History (6)

by anonymous, 8 years ago

Attachment: fusion_map.cpp added

by anonymous, 8 years ago

Attachment: fusion_map_1.53 added

by anonymous, 8 years ago

Attachment: fusion_map.error.1.55 added

comment:1 by anonymous, 8 years ago

After a discussion on the mailing list, it was determined that my use of for_each is not correct. The library should not have stepped through each item of an array in a fusion map but rather send the whole array as a type to the function called on each value. It appears that this has been fixed in 1.55.

I had a discussion on the mailing list with Agustin quoted below:

Hi Agustin thanks for your reply. You are correct that what I'm doing is not documented. In fact, it doesn't really make sense now that I look at it. The for_each should be called on each type. If the type is an array it doesn't make sense for a for_each to break down the array. That said, there should be some way to specialize operator() in the functor passed to it in order to correctly handle array types.

I missed the part where for_each was invoking the callable on each element of the array, that is not how it is supposed to be. You are right that making a recursive callable is the correct way to obtain that behavior. --

This suggests that in reality what I was doing before was actually the bug, and that 1.55 has the correct behavior.

One issue that we did find, however, is that fusion maps with std::array<T> types cannot have static initializers with 1.55.

For example,

typedef boost::fusion::map<boost::fusion::pair<struct blah, short>,

boost::fusion::pair<struct bleh, int>, boost::fusion::pair<struct foo, std::array<int, 2>>, boost::fusion::pair<struct bloog, std::string> > test_t;

test_t test{1,2, {{3,4}}, "test"};

This compiles with 1.53 but not 1.55. The {{3, 4}} is the issue.

Also interestingly enough, I have to put braces around "test" with 1.53 but not 1.55.

comment:2 by Kohei Takahashi <flast@…>, 8 years ago

I believe that it is not a fusion's bug.

The constructor of map will take their arguments by Universal References, like template <class... T> map(T &&...), to accept any types and any value categories, i.e. perfect forwarding. However, compiler cannot deduce the argument type from brace-enclosed initializer, see below.

n3337 14.8.2.1 [temp.deduct.call] p.1 sais:

If removing references and cv-qualifiers from P gives std::initializer_list<P 0 > for some P 0 and the argument is an initializer list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P 0 as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5).

and 14.8.2.5 [temp.deduct.type] p.4 sais:

If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.

comment:3 by Kohei Takahashi, 4 years ago

Milestone: To Be DeterminedBoost 1.68.0
Resolution: fixed
Status: newclosed

The problem, function returns array will be resolved in next release, by https://github.com/boostorg/fusion/pull/177 . And another issue, brace initializer is now handled by https://github.com/boostorg/fusion/issues/165 .

So I close this ticket with resolved.

Note: See TracTickets for help on using tickets.