Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying a type transformation to a list: is "const" special?

The following applies a type transformation F to a list C of types E...:

template <template <typename...> class F, typename P> struct apply_t;

template <
    template <typename...> class F,
    template <typename...> class C, typename... E
> struct apply_t <F, C <E...> > { typedef C <F <E>...> type; };

template <template <typename...> class F, typename P>
using apply = typename apply_t<F, P>::type;

Now, giving this input:

template <typename T> using map1 = T*;
template <typename T> using map2 = const T;
template <typename T> using map3 = const T*;

I get the following output in gcc 4.8.1, using e.g. std::tuple:

apply <map1, tuple <int, char> >  // -> tuple <int*, char*>  (OK)

apply <map2, tuple <int, char> >  // -> tuple <int, char>
  // (tuple <const int, const char> expected)

apply <map3, tuple <int, char> >  // -> tuple <const int*, const char*> (OK)

I can see the output types using a utility template function that calls static_assert().

I've tried all sorts of combinations. Everything works except for the map const T in particular, when given as an input type map to apply. But still works ok if I embed it in the definition of apply, i.e. typedef C <const E...> type.

On the other hand, everything works as expected in clang. I may be missing something, but it really seems like a gcc bug to me.

Any ideas?

like image 972
iavr Avatar asked Sep 16 '13 13:09

iavr


1 Answers

Here's a complete but reduced testcase, you might want to add this to the GCC bug report (if you need to write one):

template< typename T > using Map = const T;

template< template<typename> class M, typename T >
struct Apply;

template< template<typename> class M, template<typename...> class C, typename... Ts >
struct Apply< M, C<Ts...> > { typedef C<M<Ts>...> type; };

template< typename T > struct A {};
template<typename> void dummy();

int main()
{
    dummy< Apply<Map,A<int>>::type >();    
}

will fail to link because of

undefined reference to `void dummy<A<int> >()'

instead of the expected

undefined reference to `void dummy<A<const int> >()'

(I know this doesn't solve the problem, but the GCC folks will likely prefer a reduced testcase without any dependency on std::tuple or any other header).

like image 150
Daniel Frey Avatar answered Oct 16 '22 18:10

Daniel Frey