模板模板类中的非类型参数的类型在C ++ 14中不可推导,但在C ++ 17中可推导

时间:2019-03-06 23:11:07

标签: c++ templates c++14 c++17 template-templates

标题有点混乱,但是我的意思是这种特殊情况:

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'

c语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 个答案:

答案 0 :(得分:1)

[temp.deduct.type]第13和14段中的标准措词已更改。所以是的,您的示例在C ++ 14中无效,但由于具有新的语言功能,在C ++ 17中是允许的。

C ++ 14:

  

无法从非类型 template-argument 的类型推导出模板类型参数。

     

[示例:

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的{​​{1}}的类型为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]
     

-最终示例]

这似乎与另一个C ++ 17模板更改有关:C ++ 17是第一个允许在非类型模板参数中使用占位符类型的版本,例如template<class T, T i> void f(int (&a)[i]); int v[10]; void g() { f(v); // OK: T is std::size_t } template <auto Value>。我希望编译器实现需要一些类似的逻辑来支持这两种语言功能。