Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 模板参数包何时推断为空?_C++_Templates_Language Lawyer_Variadic Templates_C++2a_C++20 - Fatal编程技术网

C++ 模板参数包何时推断为空?

C++ 模板参数包何时推断为空?,c++,templates,language-lawyer,variadic-templates,c++2a,c++20,C++,Templates,Language Lawyer,Variadic Templates,C++2a,C++20,考虑以下示例(): 模板结构{使用type=int;}; 模板 void f(typename S::type){ 静态断言(sizeof…(T)==0); } 模板 void g(typename S::type,S*){} int main(){ f(42); g(42,nullptr); } GCC和Clang都对调用f感到满意,但对g的调用并不满意 在对f的调用中,虽然T.出现在非推断上下文中,但最终被推断为空。这似乎是由于: 。。。未以其他方式推导的尾部模板参数包([temp.var

考虑以下示例():

模板结构{使用type=int;};
模板
void f(typename S::type){
静态断言(sizeof…(T)==0);
}
模板
void g(typename S::type,S*){}
int main(){
f(42);
g(42,nullptr);
}
GCC和Clang都对调用
f
感到满意,但对
g
的调用并不满意

在对
f
的调用中,虽然
T.
出现在非推断上下文中,但最终被推断为空。这似乎是由于:

。。。未以其他方式推导的尾部模板参数包([temp.variadic])将被推导为模板参数的空序列

然而,在对
g
的调用中,
T..
额外出现在推导的上下文中,这会导致尝试推导并失败,这似乎会导致
g
变得不可行。似乎没有“回退”到
T..。
在尝试扣除失败后为空

  • 这种行为是故意的吗?若然,原因为何
  • 如果是这样,是否打算用“不以其他方式推断”的措词来具体说明这种行为?(也就是说,它意味着只有当包出现在没有推断的上下文中时,才会出现空回退)
  • 如果是的话,这个措辞是否足够清楚?“未以其他方式推断”的另一种解释似乎是“要么未进行推断,要么试图进行推断但失败”
。。。后续模板参数包([temp.variadic]),而不是其他形式 将推断为模板参数的空序列。

可以这样说,不以其他方式推断的条款不是一个应该以某种方式或自动放松其他一些规则的条款,或者实际上它与格式错误的原因无关(与我认为你暗示的相反)

另一个非常简单的例子可能最好地说明了这一规则:

template<class T>
void f(T, T){};

int main() {
    f(int{42},short{42});
}
或者,如果你愿意,只要

intmain(){
s1;
g(&s1,0);
}
而两者的失败原因相同

现在,如果你想允许转换-然后使用一个身份模板-这甚至适用于非推断上下文

对于您的情况,示例可能类似于():

模板
void g(typename S::type,std::type_identity_t*){}
int main(){
f(42);
g(42,nullptr);
} 
这是有效的。(注意,如果您不需要,只需自己编写身份模板)

如a中所述,将问题转过来可能会引出一个更有趣的问题


在非推导上下文中允许空模板参数推断的原因是什么?

我认为这是有意的,因为我想不出可能的替代阅读。完全没有模板:
void f(int*){}void f(double*){}void g(){f(nullptr);}
——在我看来是一致的(在模板产生的许多重载中,我们实际希望使用哪一个?).我宁愿把问题转过来:在非推断上下文中允许空模板参数推断的原因是什么?@Aconcagua可能与默认模板参数在非推断上下文中使用的原因相同@Rakete1111,因此空参数列表将被视为“默认”?似乎有点合理…@Brian Itnullptr_t是类型推断系统的死胡同。它无法从nullptr转到“指向某种S的指针”。作为一种可能的解决方法,您可以提供一个提示:模板S*sp_conv(nullptr_t zp){return zp;};然后调用g(42,sp_conv(nullptr));这适用于GCC v8和Clang v7。听起来您的观点是,只有在给定模板参数(或模板参数包)的每个推导上下文中的推导成功时,整体推导才会成功;如果同一模板参数有两个推导的上下文,并且其中一个上下文的推导失败,那么该参数就不会根据另一个上下文进行推导;相反,推导就失败了。但是,我认为你没有回答我的问题。一个人不能读到“不以其他方式推导”吗关于这种情况?从某种意义上说,这本书没有被演绎,因为演绎失败了。如果在真空中阅读,我想你是对的,它有点不清楚。也许我有预感,但我确实读到了“没有其他方式演绎”!=“演绎尝试过并失败了”和“没有其他方式演绎”=“演绎实际上没有完成”。这主要是因为其中的“否则”。这还不清楚,但可能还有改进的余地。@darune我想问标准为什么会使用主要是英国的“其他方式”(意思是“以其他方式”)
template<class T>
void f(T, T){};

int main() {
    f(int{42},short{42});
}
template <class... T>
void g(S<T...>*, S<T...>* ) {}

int main() {
    S<> s1;
    g(&s1, nullptr);
}
int main() {
    S<> s1;
    g(&s1, 0);
}
template <class... T>
void g(typename S<T...>::type, std::type_identity_t<S<T...> >*) {}

int main() {
    f(42);
    g(42, nullptr);
}