vittorioromeo / scelta

(experimental) Syntactic sugar for variant and optional types.
https://vittorioromeo.info
MIT License
157 stars 10 forks source link

Cannot `map` to a different type #11

Closed TartanLlama closed 6 years ago

TartanLlama commented 6 years ago

Adding the following code to optional_monadic.cpp:

auto a = make();
auto f = [](auto x){return "oh no";};
scelta::map(a, f);

results in this error on GCC 7.2 (cut down for brevity):

In file included from /home/simon/scelta/include/scelta/utils.hpp:13:0,
                 from /home/simon/scelta/test/optional/../variant_test_utils.hpp:9,
                 from /home/simon/scelta/test/optional/optional_monadic.cpp:2:
/home/simon/scelta/include/scelta/./utils/optional_monadic.hpp:29:20: note: candidate: template<class Optional, class T, class F> constexpr decltype ((scelta::is_nullopt(o) ? forward<decltype (def)>(def) : forward<decltype (f)>(f)(scelta::impl::access_optional(forward<decltype (o)>(o))))) scelta::map_or(Optional&&, T&&, F&&)
     constexpr auto map_or(Optional&& o, T&& def, F&& f)
                    ^~~~~~
/home/simon/scelta/include/scelta/./utils/optional_monadic.hpp:29:20: note:   template argument deduction/substitution failed:
In file included from /home/simon/scelta/include/scelta/./support/./variant/./enable/../../../traits/adt/../dispatch.hpp:8:0,
                 from /home/simon/scelta/include/scelta/./support/./variant/./enable/../../../traits/adt/valid.hpp:7,
                 from /home/simon/scelta/include/scelta/./support/./variant/./enable/std.hpp:10,
                 from /home/simon/scelta/include/scelta/./support/./variant/std.hpp:13,
                 from /home/simon/scelta/include/scelta/./support/variant.hpp:7,
                 from /home/simon/scelta/include/scelta/support.hpp:7,
                 from /home/simon/scelta/test/optional/../variant_test_utils.hpp:8,
                 from /home/simon/scelta/test/optional/optional_monadic.cpp:2:
/home/simon/scelta/include/scelta/./utils/optional_monadic.hpp: In substitution of ‘template<class Optional, class T, class F> constexpr decltype ((scelta::is_nullopt(o) ? forward<decltype (def)>(def) : forward<decltype (f)>(f)(scelta::impl::access_optional(forward<decltype (o)>(o))))) scelta::map_or(Optional&&, T&&, F&&) [with Optional = boost::optional<int>&; T = boost::optional<int>; F = main()::<lambda(auto:15)> [with auto:15 = test::impl::maker_t<boost::optional<int> >]::<lambda(auto:16)>&]’:
/home/simon/scelta/include/scelta/./utils/optional_monadic.hpp:39:5:   required by substitution of ‘template<class Optional, class F> constexpr decltype (scelta::map_or(forward<decltype (o)>(o), std::decay_t<_Tp>{}, forward<decltype (f)>(f))) scelta::map(Optional&&, F&&) [with Optional = boost::optional<int>&; F = main()::<lambda(auto:15)> [with auto:15 = test::impl::maker_t<boost::optional<int> >]::<lambda(auto:16)>&]’
/home/simon/scelta/test/optional/optional_monadic.cpp:130:28:   required from ‘main()::<lambda(auto:15)> [with auto:15 = test::impl::maker_t<boost::optional<int> >]’
/home/simon/scelta/test/optional/../variant_test_utils.hpp:117:28:   required from ‘test::with_all_optional_implementations(TF&&)::<lambda(auto:14)> [with auto:14 = test::impl::unpack_alternatives<test::impl::alternatives_t<int> >::applier<boost::optional>; TAlternative = int; TF = main()::<lambda(auto:15)>]’
/home/simon/scelta/test/optional/../variant_test_utils.hpp:91:10:   required from ‘void test::instantiate_with_all_optional_implementations(TF&&) [with TestCase = test::impl::unpack_alternatives<test::impl::alternatives_t<int> >::applier; TF = test::with_all_optional_implementations(TF&&) [with TAlternative = int; TF = main()::<lambda(auto:15)>]::<lambda(auto:14)>]’
/home/simon/scelta/test/optional/../variant_test_utils.hpp:116:80:   required from ‘void test::with_all_optional_implementations(TF&&) [with TAlternative = int; TF = main()::<lambda(auto:15)>]’
/home/simon/scelta/test/optional/optional_monadic.cpp:134:10:   required from here
/home/simon/scelta/include/scelta/./utils/optional_monadic.hpp:31:23: error: operands to ?: have different types ‘boost::optional<int>’ and ‘const char*’
         is_nullopt(o) ? FWD(def)
         ~~~~~~~~~~~~~~^~~~~~~~~~
                       : FWD(f)(impl::access_optional(FWD(o)))

Expected behaviour: Compile and run

and_then has a similar issue.

A fix would be to get the return type of calling f with the value in the optional and explicitly construct the correct type on both branches of the conditional.

vittorioromeo commented 6 years ago

Nasty! Will look into this.

vittorioromeo commented 6 years ago

Should be fixed in #14, thanks!