How to access the internal typedef template present in the members of the Variadic template argument package?

I have code that seems unambiguous to me, but gcc4.7 is choking on it:

#include <iostream> #include <tuple> using namespace std; // Container for mixins template<template<typename> class... Mixins> struct Mix : Mixins<Mix<Mixins...>>... { typedef tuple<Mixins<Mix<Mixins...>>...> types; }; // Outer layer extracts the type tuple from the argument template<typename T> struct InnerCombiner { typedef typename InnerCombiner<typename T::types>::type type; }; // Typedef type to be a new mix of the inner mixins of the MixedMixins template<typename... MixedMixins> struct InnerCombiner<tuple<MixedMixins...>> { // This line is the problem. The compiler doesn't seem to be able to make sense // of the reference to the inner mixin template template classes typedef Mix<MixedMixins::InnerMixin...> type; }; template<typename Mixed> struct A { template<typename MixedInner> struct InnerMixin { void foo() { cout << "foo() loves you!" << endl; }; }; }; template<typename Mixed> struct B { template<typename MixedInner> struct InnerMixin { void bar() { cout << "bar() loves you!" << endl; }; }; }; // I'm going to write out the type I expect ic to have. Oh god, it so nasty: // Mix< // A<Mix<A,B>>::InnerMixin<Mix<A<Mix<A,B>>::InnerMixin,B<Mix<A,B>>::InnerMixin>, // B<Mix<A,B>>::InnerMixin<Mix<A<Mix<A,B>>::InnerMixin,B<Mix<A,B>>::InnerMixin> // > int main() { InnerCombiner<Mix<A,B>>::type ic; ic.bar(); // Not working. } 

Is there something wrong with accessing InnerMixins this way? It was pretty reasonable when I wrote this :)

+4
source share
2 answers

I can get it to work on clang 3.0 by specifying an InnerMixin template:

 typedef Mix<MixedMixins::template InnerMixin...> type; // ^^^^^^^^ 

but it still does not work on g ++ 4.8, with

  3.cpp: 23: 52: error: parameter packs not expanded with '...':
 3.cpp: 23: 52: note: 'MixedMixins'
+4
source

There is a type / value mismatch, this should be at least MixedMixins::template InnerMixin... However, GCC still refuses this, and I did not find a way to persuade him. Unfortunately, I can hardly prove that such a package extension is really valid. I hope someone more knowledgeable in grammar could answer this question.


In a more β€œlateral” approach, did you consider that the template template parameters completely match? Not only will this alleviate the pain of syntax, but you can still "rebuild" the template specialization template parameters:

 // We accept two types, a template specialization and // a sequence of would be template parameters. template<typename Specialization, typename T> struct rebind; template< template<typename...> class Template , typename... Old template<typename...> class Sequence , typename... T > struct rebind<Template<Old...>, Sequence<T...>> { using type = Template<T...>; }; template<typename S, typename... T> using Rebind = typename rebind<S, T...>::type; 

eg. Rebind<std::vector<int>, std::tuple<double, std::allocator<double>> - std:vector<double> . Combine this with the parameters_of / ParametersOf utility to extract the parameters of the specialization template, for example. a std::tuple .

As a disclaimer, I did not use these methods on my own, but I already appreciated how I can limit the template parameters to a pain with a few centralized spots of my code.

+1
source

Source: https://habr.com/ru/post/1402380/


All Articles