Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC/CLang disagree on partial specialization of template template parameter

GCC and clang disagree about this code.

#include <type_traits>

template <typename T, template <typename...> typename Tpl> 
struct storage {
    using type_t = T;

    template <typename... Args>
    using storage_tpl = Tpl<Args...>;
};

template <typename T, template <typename...> typename>
struct F{
    constexpr static int x = 1;
};

template <typename T >
struct F<T, std::void_t>{
    constexpr static int x = 2;
};

int f() {
    using S = storage<int, std::void_t>;

    static_assert(F<int, S::storage_tpl>().x == 2);

    return F<int, S::storage_tpl>().x;
}

According to clang S::storage_tpl is not std::void_t; of consequence it selects the primary template F instead of the partial specialization and thus the assert.

At first glance, it looks like GCC is right because it understands that the nested template is just an alias for std::void_t but maybe it is too smart and the standard requires that S::storage_tpl and std::void_t must be two different templates.

Who is right?

like image 880
dvd Avatar asked Oct 09 '18 15:10

dvd


1 Answers

It looks like this is unspecified at the moment and h/t to T.C. it looks like this is covered by CWG defect report 1286 which says:

Issue 1244 was resolved by changing the example in 17.5 [temp.type] paragraph 1 from

 template<template<class> class TT> struct X { };
  template<class> struct Y { };
  template<class T> using Z = Y<T>;
  X<Y> y;
  X<Z> z;

to

  template<class T> struct X { };
  template<class> struct Y { };
  template<class T> using Z = Y<T>;
  X<Y<int> > y;
  X<Z<int> > z;

In fact, the original intent was that the example should have been correct as written; however, the normative wording to make it so was missing. The current wording of 17.6.7 [temp.alias] deals only with the equivalence of a specialization of an alias template with the type-id after substitution. Wording needs to be added specifying under what circumstances an alias template itself is equivalent to a class template.

and proposed the following resolution:

Add the following as a new paragraph following 17.6.7 [temp.alias] paragraph 2:

When the type-id in the declaration of alias template (call it A) consists of a simple-template-id in which the template-argument-list consists of a list of identifiers naming each template-parameter of A exactly once in the same order in which they appear in A's template-parameter-list, the alias template is equivalent to the template named in the simple-template-id (call it T) if A and T have the same number of template-parameters. [Footnote: This rule is transitive: if an alias template A is equivalent to another alias template B that is equivalent to a class template C, then A is also equivalent to C, and A and B are also equivalent to each other. —end footnote] [Example:

  template<typename T, U = T> struct A;

  template<typename V, typename W>
    using B = A<V, W>;                // equivalent to A

  template<typename V, typename W>
    using C = A<V>;                   // not equivalent to A:
                                      // not all parameters used

  template<typename V>
    using D = A<V>;                   // not equivalent to A:
                                      // different number of parameters

  template<typename V, typename W>
    using E = A<W, V>;                // not equivalent to A:
                                      // template-arguments in wrong order

  template<typename V, typename W = int>
    using F = A<V, W>;                // equivalent to A:
                                      // default arguments not considered

  template<typename V, typename W>
    using G = A<V, W>;                // equivalent to A and B

  template<typename V, typename W>
    using H = E<V, W>;                // equivalent to E

  template<typename V, typename W>
    using I = A<V, typename W::type>; // not equivalent to A:
                                      // argument not identifier

—end example]

but there are issues with this resolution and the defect report is still active.

like image 106
Shafik Yaghmour Avatar answered Nov 01 '22 09:11

Shafik Yaghmour