c++c++11gcclibstdc++gcc4.8

main()::__lambda1 is not an accessible base of std::_Tuple_impl<1ul, main()::__lambda1>


Take the following:

#include <utility>
#include <functional>
#include <iostream>

struct FooType
{
    FooType(std::tuple<std::function<void()>, std::function<void()>> t)
    {
        std::get<0>(t)();
        std::get<1>(t)();
    }
};

int main()
{
    FooType foo(
        std::make_tuple(
            []() { std::cout << "a\n"; },
            []() { std::cout << "b\n"; }
        )
    );
}

It builds and runs fine with GCC 4.9 and higher, but with GCC 4.8 (which is my build system) the following compiler error results:

In file included from main.cpp:2:0:
/usr/include/c++/4.8/functional: In substitution of 'template<class _Res, class ... _ArgTypes> template<class _Functor> using _Invoke = decltype (std::__callable_functor(declval<_Functor&>())((declval<_ArgTypes>)()...)) [with _Functor = std::_Tuple_impl<1ul, main()::__lambda1>; _Res = void; _ArgTypes = {}]':
/usr/include/c++/4.8/functional:2257:9:   required from 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _UHead, _UTails ...>&&) [with _UHead = main()::__lambda0; _UTails = {main()::__lambda1}; long unsigned int _Idx = 0ul; _Head = std::function<void()>; _Tail = {std::function<void()>}]'
/usr/include/c++/4.8/tuple:556:60:   required from 'constexpr std::tuple<_T1, _T2>::tuple(std::tuple<_U1, _U2>&&) [with _U1 = main()::__lambda0; _U2 = main()::__lambda1; <template-parameter-2-3> = void; _T1 = std::function<void()>; _T2 = std::function<void()>]'
main.cpp:21:5:   required from here
/usr/include/c++/4.8/functional:2181:71: error: 'main()::__lambda1' is not an accessible base of 'std::_Tuple_impl<1ul, main()::__lambda1>'
  using _Invoke = decltype(__callable_functor(std::declval<_Functor&>())
                                                                       ^

Presumably I've hit a "bug" in GCC 4.8's experimental C++11 implementation, but I can't find any discussion about it online. Is this issue familiar to anyone? Is there a cheap workaround?

Passing std::function in tuples is core to the design I've just created — shame on me for building it in Coliru without switching to GCC 4.8 specifically until the end!


Solution

  • Creating a tuple with explicit template arguments works as a workaround:

    #include <utility>
    #include <functional>
    #include <iostream>
    
    struct FooType
    {
        FooType(std::tuple<std::function<void()>, std::function<void()>> t)
        {
            std::get<0>(t)();
            std::get<1>(t)();
        }
    };
    
    int main()
    {
        FooType foo(
            std::make_tuple
            <
                std::function<void()>,
                std::function<void()>
            >(
                []() { std::cout << "a\n"; },
                []() { std::cout << "b\n"; }
            )
        );
    }