Тип не типового параметра в шаблонном шаблонном классе не выводим в C ++ 14, но выводим в C ++ 17 - PullRequest
2 голосов
/ 07 марта 2019

Название немного сбивает с толку, но я имею в виду этот конкретный случай:

template<class>
struct get_type_of_nontype;

template<class T, T Value, template<T> class Template>
struct get_type_of_nontype<Template<Value>> {
    using type = T;
};

Так что я могу использовать его так:

#include <type_traits>

template<int I>
class int_non_type {};

static_assert(
    std::is_same<typename get_type_of_nontype<int_non_type<0>>::type, int>::value,
    "T is deduced to be `int` as `template<T> class Template` is `template<int> class int_non_type`"
);

Это отлично работает в C ++17.В C ++ 14 я получаю следующие ошибки:

gcc 8:

<source>:5:8: error: template parameters not deducible in partial specialization:
struct get_type_of_nontype<Template<Value>> {
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:5:8: note:         'T'

clang 7:

<source>:5:8: error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used [-Wunusable-partial-specialization]
struct get_type_of_nontype<Template<Value>> {
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:4:16: note: non-deducible template parameter 'T'
template<class T, T Value, template<T> class Template>
               ^

И затем они оба жалуются, что struct get_type_of_nontype<int_non_type<0>>является неполным, поэтому typename get_type_of_non_type<int_non_type<0>>::type не может скомпилировать.

Почему это отличается между C ++ 14 и C ++ 17?Это просто ошибка компилятора?Если нет, есть ли способ сделать это в C ++ 14?

1 Ответ

1 голос
/ 07 марта 2019

Стандартная формулировка в [temp.deduct.type] параграфах 13 и 14 изменилась.Так что да, ваш пример недопустим в C ++ 14, но разрешен в C ++ 17 благодаря новой языковой функции.

C ++ 14:

ШаблонАргумент типа не может быть выведен из типа нетипичного аргумента шаблона .

[ Пример:

template<class T, T i> void f(double a[10][i]);
int v[10][20];
f(v);           // error: argument for template-parameter T cannot be deduced

- конец примера ]

C ++ 17:

Когда значение аргумента соответствует параметру шаблона нетипичного типа P, то естьобъявленный с зависимым типом выводится из выражения, параметры шаблона в типе P выводятся из типа значения.[ Пример:

template<long n> struct A { };

template<typename T> struct C;
template<typename T, T n> struct C<A<n>> {
  using Q = T;
};

using R = long;
using R = C<A<2>>::Q;    // OK; T was deduced to long from the
                         // template argument value in the type A<2>

- конец примера ] Тип N в типе T[N] равен std::size_t.[ Пример:

template<typename T> struct S;
template<typename T, T n> struct S<int[n]> {
  using Q = T;
};

using V = decltype(sizeof 0);
using V = S<int[42]>::Q;  // OK; T was deduced to std::size_t from the type int[42]

- конец примера ]

[ Пример:

template<class T, T i> void f(int (&a)[i]);
int v[10];
void g() {
  f(v);         // OK: T is std::size_t
}

- end example ]

Это, похоже, связано с другим изменением шаблона C ++ 17: C ++ 17 является первой версией, которая позволяет заполнять типы внетиповые параметры шаблона, как в template <auto Value> или template <auto* Ptr>.Я ожидаю, что реализации компилятора будут нуждаться в некоторой схожей логике для поддержки обеих функций языка.

...