模板参数包何时推断为空?
When are template parameter packs deduced as empty?
考虑以下示例(Coliru 链接):
template <class... T> struct S { using type = int; };
template <class... T>
void f(typename S<T...>::type) {
static_assert(sizeof...(T) == 0);
}
template <class... T>
void g(typename S<T...>::type, S<T...>*) {}
int main() {
f(42);
g(42, nullptr);
}
GCC和Clang都对f
的召唤感到满意,但对g
的召唤却不满意。
在对f
的调用中,虽然T...
出现在非推导的上下文中,但它最终被推导为空。这似乎是由于 [temp.arg.explicit]/4:
。未以其他方式推导的尾随模板参数包 ([temp.variadic]) 将被推导为模板参数的空序列。...
然而,在对g
的呼吁中,T...
还出现在推导的上下文中,导致演绎尝试和失败,这一事实似乎导致g
变得不可行。一旦尝试扣除并失败,似乎没有"后备"T...
空。
- 这种行为是有意的吗?如果是这样,为什么?
- 如果是这样,是否打算用"未以其他方式推断"的措词具体说明这种行为?(即,这意味着空回退仅在包没有出现在推导的上下文中时才会发生)
- 如果是这样,这个措辞是否足够清楚?似乎对"未以其他方式推断"的合理替代解读是"要么没有进行演绎,要么尝试演绎但失败了"。
...尾随模板参数包 ([temp.variadic]) 不是其他 推导将推导为模板参数的空序列。 ...
可以说,未以其他方式推导的不是应该以某种方式或自动放宽其他规则的条款,或者实际上它与它为什么格式不正确无关(与我认为你暗示的相反)。
另一个规则也许可以用另一个非常简单的例子来最好地证明:
template<class T>
void f(T, T){};
int main() {
f(int{42},short{42});
}
以上编译失败。为什么?因为即使short
无缝转换为int
(促销),它也不是同一类型。
此外,由于nullptr
只是具有某种普通类型的std::nullptr_t
- 因此根本不适合参与模板参数推导。
因此,让我们暂时忘记非推导的上下文,并尝试使用推导的上下文:
template <class... T>
void g(S<T...>*, S<T...>* ) {}
int main() {
S<> s1;
g(&s1, nullptr);
}
或者如果你愿意,只需
int main() {
S<> s1;
g(&s1, 0);
}
两者都因同样的原因而失败。
现在,如果您想允许转换 - 请使用身份模板 - 这甚至适用于非推断上下文!
对于您的情况,示例可能如下所示 (c++2a):
template <class... T>
void g(typename S<T...>::type, std::type_identity_t<S<T...> >*) {}
int main() {
f(42);
g(42, nullptr);
}
这是有效的。(注意,如果你没有 C++20,只需自己编写标识模板)
正如评论中所述,扭转问题可能会导致一个更有趣的问题?
在非推导上下文中允许空模板参数推导的原因是什么?
相关文章:
- 如何反转整数参数包
- 如何将enable-if与模板参数和参数包一起使用
- 模板元编程:如何将参数包组合成新的参数包
- C ++:在构造函数中使用参数包?
- 如何使我的 sizeof sum 结构与空参数包一起工作
- 双模板参数包
- 参数包构造函数在类模板中隐藏用户定义的转换
- 嵌套参数包扩展失败
- 参数包中的筛选器类型
- 参数和参数包的类型推导
- 为模板参数包添加别名
- enable_if中参数包的大小问题
- 如何使特征接受参数包?
- 参数包内 noexcept 说明符
- 获取可变参数模板参数包的相关类型
- 模板参数包指针的大小
- 显式指定的模板参数包
- 实例化模板时,我是否必须显式显示参数包中的类型?
- 通过跳过可选参数来填充参数包
- 模板参数包何时推断为空?