http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53236

--- Comment #3 from Daniel Krügler <daniel.kruegler at googlemail dot com> 
2012-05-05 18:57:03 UTC ---
Reduced test-case:

//-----
template<typename, typename, typename>
struct enable_same
{};

template<typename T, typename U>
struct enable_same<T, T, U>
{
  typedef U type;
};

template <typename ...Ts>
struct other_variant
{
  void get(){}
};

template <typename T, typename ...Ts>
struct other_variant<T, Ts...> : other_variant<Ts...>
{
  T u;

  using other_variant<Ts...>::get;

  template <typename T2>
  typename enable_same<T, T2, T>::type
  get()    { return u; }
};

int main()
{
  other_variant<int, double> ov;
  ov.get<double>();
}
//-----

It should be added, that it is important that other_variant has a second
template argument of double here (e.g. 'bool' won't work): It seems as if
within the member template get of the  partial specialization T behaves as if
it were type double within this member declaration. The hypotheses becomes some
evidence, if we change the implementation of the get template as follows:

  template <typename T2>
  typename enable_same<T, T2, T>::type
  get()    {
    typename enable_same<T, double, bool>::type dummy;
    return u;
  }

This also is accepted, even though T is of type int.

The curiosity increases about the interpretation of the deduced type of 'T'
within the partial specialization, if we add seemingly contradictory typedefs
to the class body of the specialization as follows:

//---
template<typename, typename, typename>
struct enable_same
{};

template<typename T, typename U>
struct enable_same<T, T, U>
{
  typedef U type;
};

template <typename ...Ts>
struct other_variant
{
  void get(){}
};

template <typename T, typename ...Ts>
struct other_variant<T, Ts...> : other_variant<Ts...> // Line 18
{
  T u;

  typename enable_same<T, int, wchar_t>::type dummy1; // L. 22: Should be OK
  typename enable_same<T, double, char>::type dummy2; // Should be an error

  using other_variant<Ts...>::get;

  template <typename T2>
  typename enable_same<T, T2, T>::type
  get()    {
    typename enable_same<T, double, bool>::type dummy; // Should be an error
    return u;
  }
};

int main()
{
  other_variant<int, double> ov; // Line 37
  ov.get<double>();
}
//---

On gcc 4.8.0 20120429 (experimental) I get the following diagnostics:

18|  required from 'struct other_variant<int, double>'|
37|  required from here|
22|error: no type named 'type' in 'struct enable_same<double, int, wchar_t>'|
37|  required from here|
23|error: no type named 'type' in 'struct enable_same<int, double, char>'|
38|  required from here|
30|warning: unused variable 'dummy' [-Wunused-variable]|

Note that lines 22 and 23 describe the affected instantiations as

enable_same<double, int, wchar_t>

and

enable_same<int, double, char>

thus T seems to be once double and once int within the same instantiation -
quite amusing ;-)

Reply via email to