https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78282

            Bug ID: 78282
           Summary: [6/7 Regression] Overload resolution failure, in
                    parameter pack expansion, inside a template class
           Product: gcc
           Version: 6.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kholdstare0.0 at gmail dot com
  Target Milestone: ---

Created attachment 40009
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=40009&action=edit
Preprocessed source. Changing "auto" to "Key" on line 21037 fixes the issue.

Hi,

Apologies in advance for such a large example, I couldn't simplify it any more
and trigger the behavior. Here is the minimal source:

        #include <tuple>
        #include <utility>

        template <typename... Ts>
        struct my_tuple : std::tuple<Ts...>
        {
        private:
                using base_t = std::tuple<Ts...>;
        public:
                using base_t::base_t;
        };

        using std::get;

        #define TRIGGER_BUG 1
        #if TRIGGER_BUG  
        template <typename Key, typename... Ts>
        auto && get(my_tuple<Ts...>&& m)
        {
                return std::get<Key>(std::move(m));
        }

        #else
        template <typename Key, typename... Ts>
        Key && get(my_tuple<Ts...>&& m)
        {
                return std::get<Key>(std::move(m));
        }  
        #endif

        namespace detail
        {
                template <typename... Ts>
                struct inheritor
                {
                private:
                        using storage_type = my_tuple<Ts...>;
                        storage_type values_;

                public:
                        template <typename Derived>
                        struct impl : private Ts::impl...
                        {
                                public:
                                        impl(inheritor&& unsealed)
                                                : impl(std::move(unsealed),
std::index_sequence_for<Ts...>{})
                                                { }

                                        template <size_t... indices>
                                                impl(inheritor&& outer,
std::index_sequence<indices...>)
                                                :
Ts::impl(get<indices>(std::move(outer.values_)))...
                                                { }
                        };

                        inheritor(storage_type&& values)
                                : values_(std::move(values))
                        { }
                };
        }

        struct null_node
        {
                struct impl
                {
                        impl(null_node&&) { }
                };
        };

        void test()
        {
                detail::inheritor<null_node>
example{std::forward_as_tuple(null_node{})};
                struct whatever {};
                detail::inheritor<null_node>::impl<whatever>
result(std::move(example));
        }



I have also attached the preprocessed source. Here is the example on godbolt:
https://godbolt.org/g/4i1v31



Here is the error:

        main.cpp: In instantiation of
'detail::inheritor<Ts>::impl<Derived>::impl(detail::inheritor<Ts>&&,
std::index_sequence<indices ...>) [with long unsigned int ...indices = {0ul};
Derived = test()::whatever; Ts = {null_node}; std::index_sequence<indices ...>
= std::integer_sequence<long unsigned int, 0ul>]':
        main.cpp:46:66:   required from
'detail::inheritor<Ts>::impl<Derived>::impl(detail::inheritor<Ts>&&) [with
Derived = test()::whatever; Ts = {null_node}]'
        main.cpp:73:72:   required from here
        main.cpp:51:56: error: no matching function for call to
'null_node::impl::impl()'
                  : Ts::impl(get<indices>(std::move(outer.values_)))...

                                                                               
                                        ^~~
        main.cpp:65:3: note: candidate: null_node::impl::impl(null_node&&)
           impl(null_node&&) { }

           ^~~~
        main.cpp:65:3: note:   candidate expects 1 argument, 0 provided
        main.cpp:63:9: note: candidate: constexpr null_node::impl::impl(const
null_node::impl&)
          struct impl

                         ^~~~
        main.cpp:63:9: note:   candidate expects 1 argument, 0 provided
        main.cpp:63:9: note: candidate: constexpr
null_node::impl::impl(null_node::impl&&)
        main.cpp:63:9: note:   candidate expects 1 argument, 0 provided


It seems to be a weird interaction between "lockstep" parameter pack expansion,
overload resolution and auto type deduction. Things to note:

* I bring std::get into scope
* my_tuple is a light wrapper around std::tuple that allows a more specific
overload to be made for the get function. Note this is the get by type rather
than by index.
* Later in inheritor::impl I am constructing base classes by grabbing them from
my_tuple using the index_sequence trick. I am calling get for indices.
* The extra 'get' overload for my_tuple somehow confuses the compiler, causing
it to default construct all the bases.
* This problem ONLY occurs if the extra overload uses auto type deduction.

Reply via email to