类型别名和模板模板参数推导
Type aliases and template template argument deduction
问题:
我注意到在使用类型别名时,模板推导过程中存在一点不一致。特别是类型别名可以用作模板模板参数,但不能推导为一个。
示例:
我们将使用 Matched<Type>
来查看 Type
是否是模板类型的实例。
template <typename T>
bool Matched = false;
template <template <typename> typename F, typename T>
bool Matched<F<T>> = true;
现在定义一个类型别名
template<typename T>
using Alias = std::tuple<T,T>;
我的问题是 Matched<Alias<int>>==false
。但是 Alias
可以用作模板模板参数,例如:
template<template<typename> typename F>
using ApplyInt = F<int>;
然后 ApplyInt<Alias>
工作正常。
回顾一下,在 ApplyInt<Alias>
中被视为模板模板参数,但在 Matched<Alias<int>>
中则不然。我觉得这有点愚蠢,因为我认为类型别名是类型上的函数,我想使用它们。现在,与类型相比,类型别名被视为第二 class 公民,这使得很难以通用方式使用它们,例如组合或转换它们。
可能的出路:
1.Change 推导规则,这样类型别名被检测为模板模板参数。这将使 Matched<Alias>==true
.
2.Allow using
在模板声明中的用法如下:
template<template<typename> using T, typename T>
bool Matched<F<T>> = true;
问题:
这种行为是故意的吗?这是疏忽吗?这是否已被注意到并且会在未来的 c++ 版本中得到修复?
附带说明:类似的问题是变量模板。为什么我们不能写?
template <template<typename> auto Var>
auto VarForInt = Var<int>;
编辑(接受答案后):
我对类型推导感到非常困惑。当我们在助手中存储类型别名时 class
template<template<typename> typename F>
struct Helper{};
我们有一个函数
template<template<typename> typename F>
void foo(Helper<F>){}
我们可以调用foo(Helper<Alias>{})
。 Alias
"deduced" 不是在函数调用中吗?或者这不叫类型推导?
是的,那是故意的。正如您所说,别名模板确实有点像 "second class citizen"。首先,不能专门化别名模板,这是一个非常重要的提示。
现在,他们的 "lower grade" 在您的示例中很明显是关于 [temp.alias]/2:
When a template-id refers to the specialization of an alias
template, it is equivalent to the associated type obtained by
substitution of its template-arguments for the template-parameters
in the type-id of the alias template. [ Note: An alias template name
is never deduced. — end note ]
上面的意思是,当你写Matched<Alias<int>>
时,由于Alias<int>
指的是别名模板的特化,它相当于直接写Matched<std::tuple<int,int>>
。很明显为什么它与专用变量模板不匹配。
这不是疏忽,也不会修复。别名模板可以为更复杂的模板表达式提供 shorthand。而且您不希望调用错误的重载,或者实例化错误的模板特化,因为您使用了 shorthand 而不是整个复杂表达式。
问题:
我注意到在使用类型别名时,模板推导过程中存在一点不一致。特别是类型别名可以用作模板模板参数,但不能推导为一个。
示例:
我们将使用 Matched<Type>
来查看 Type
是否是模板类型的实例。
template <typename T>
bool Matched = false;
template <template <typename> typename F, typename T>
bool Matched<F<T>> = true;
现在定义一个类型别名
template<typename T>
using Alias = std::tuple<T,T>;
我的问题是 Matched<Alias<int>>==false
。但是 Alias
可以用作模板模板参数,例如:
template<template<typename> typename F>
using ApplyInt = F<int>;
然后 ApplyInt<Alias>
工作正常。
回顾一下,在 ApplyInt<Alias>
中被视为模板模板参数,但在 Matched<Alias<int>>
中则不然。我觉得这有点愚蠢,因为我认为类型别名是类型上的函数,我想使用它们。现在,与类型相比,类型别名被视为第二 class 公民,这使得很难以通用方式使用它们,例如组合或转换它们。
可能的出路:
1.Change 推导规则,这样类型别名被检测为模板模板参数。这将使 Matched<Alias>==true
.
2.Allow using
在模板声明中的用法如下:
template<template<typename> using T, typename T>
bool Matched<F<T>> = true;
问题:
这种行为是故意的吗?这是疏忽吗?这是否已被注意到并且会在未来的 c++ 版本中得到修复?
附带说明:类似的问题是变量模板。为什么我们不能写?
template <template<typename> auto Var>
auto VarForInt = Var<int>;
编辑(接受答案后):
我对类型推导感到非常困惑。当我们在助手中存储类型别名时 class
template<template<typename> typename F>
struct Helper{};
我们有一个函数
template<template<typename> typename F>
void foo(Helper<F>){}
我们可以调用foo(Helper<Alias>{})
。 Alias
"deduced" 不是在函数调用中吗?或者这不叫类型推导?
是的,那是故意的。正如您所说,别名模板确实有点像 "second class citizen"。首先,不能专门化别名模板,这是一个非常重要的提示。
现在,他们的 "lower grade" 在您的示例中很明显是关于 [temp.alias]/2:
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template. [ Note: An alias template name is never deduced. — end note ]
上面的意思是,当你写Matched<Alias<int>>
时,由于Alias<int>
指的是别名模板的特化,它相当于直接写Matched<std::tuple<int,int>>
。很明显为什么它与专用变量模板不匹配。
这不是疏忽,也不会修复。别名模板可以为更复杂的模板表达式提供 shorthand。而且您不希望调用错误的重载,或者实例化错误的模板特化,因为您使用了 shorthand 而不是整个复杂表达式。