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++ 当函数模板参数是具有默认参数的类模板时,模板参数推断如何执行 模板 结构测试{}; 模板 无效函数(测试){/#1 } int main(){ func(Test{});/#2 }_C++_Templates_Language Lawyer - Fatal编程技术网

C++ 当函数模板参数是具有默认参数的类模板时,模板参数推断如何执行 模板 结构测试{}; 模板 无效函数(测试){/#1 } int main(){ func(Test{});/#2 }

C++ 当函数模板参数是具有默认参数的类模板时,模板参数推断如何执行 模板 结构测试{}; 模板 无效函数(测试){/#1 } int main(){ func(Test{});/#2 },c++,templates,language-lawyer,C++,Templates,Language Lawyer,考虑上述代码,在调用函数模板func时,参数类型为Test,调用函数模板时,将执行模板参数推断 函数调用的模板参数推断规则为: 模板参数推导是通过将包含参与模板参数推导的模板参数的每个函数模板参数类型(称为p)与调用的相应参数类型(称为A)进行比较来完成的,如下所述 我很确定A的类型是Test,但是我不确定p的类型是什么。是Test还是Test,根据规则,似乎P的类型是Test,然后执行演绎过程以确定参与模板参数演绎的T的值。然后根据这些规则描述如下: 一般来说,演绎过程试图找到模板参数值,

考虑上述代码,在调用函数模板
func
时,参数类型为
Test
,调用函数模板时,将执行模板参数推断

函数调用的模板参数推断规则为:

模板参数推导是通过将包含参与模板参数推导的模板参数的每个函数模板参数类型(称为p)与调用的相应参数类型(称为A)进行比较来完成的,如下所述

我很确定
A
的类型是
Test
,但是我不确定
p
的类型是什么。是
Test
还是
Test
,根据规则,似乎
P
的类型是
Test
,然后执行演绎过程以确定参与模板参数演绎的
T
的值。然后根据这些规则描述如下:

一般来说,演绎过程试图找到模板参数值,使演绎的A与A相同(在类型A如上所述转换后)

当从默认模板参数推导或获取所有模板参数时,模板和函数类型的模板参数列表中模板参数的所有使用都将替换为相应的推导或默认参数值

因为类模板
Test
有一个默认参数,因此推导出的
T
被替换为默认参数。这意味着导出的
A
Test
,它与参数类型
Test
相同

然而,这只是我的理解。我不确定这里的
P
是什么类型的。如果将函数参数的类型更改为
测试
,则将报告:

candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'double')
结果看起来好像
p
Test
,并且
T
的第一个值与
T
的第二个值冲突

所以,我的问题是:


这里的
p
Test
还是
Test
?为什么呢?

我试着想出一个只强制进行类推导而不强制进行函数推导的代码。
此处没有函数实例化,但编译器仍会发出错误:

template<typename T, typename U = T>
struct Test{};

template<typename T> 
void func(Test<T, T>){
}

template<typename T>
void func(Test<T>){  
}
模板
结构测试{};
模板
无效函数(测试){
}
模板
无效函数(测试){
}
重新定义“模板无效功能(测试)”

GCC:
叮当声:

先前的错误答案:

p是模板参数,而不是模板本身。在声明
Test
P指的是T,而不是Test。因此在实例化
Test
T是int,就像调用中的A也是int一样

没有语言律师的回答

没有类型
Test
实际上是
Test
的“速记”


就像默认函数参数一样,如果你有
intfoo(inta,intb=24)
函数的类型是
int(int,int)
,任何像
foo(11)
这样的调用实际上都是
foo(11,24)
p
必须是类型而不是模板
test
是一个模板id,但标准中没有明确说明模板id
test
等同于
test
。唯一要说的是:

模板id在以下情况下有效:

  • [……]
  • 每个不可推断的非打包参数都有一个参数,该参数没有默认的模板参数[…]
在那之后,标准中的漏洞被我们的直觉所填补,我们的直觉通过使用术语默认来引导

我认为这里的关键点是模板指定了一个族,而模板id不能指定一个族

这里的
p
Test
还是
Test
?为什么

p
Test


我认为我们可以同意,规则也适用于类模板;e、 g.涉及类模板专门化的偏序,完全基于将类模板重新写入(发明的)函数模板的概念,并将函数模板的规则应用于偏序分析下与原始类模板相对应的发明函数模板的规则。与函数模板相比,类模板的标准段落非常简短,结合这一事实,我认为下面的参考文献也适用于类模板

现在,从[强调我的]:

引用函数模板专用化时,所有模板参数应具有值。可以明确指定值,或者在某些情况下,可以从使用中推断出值,或者从默认的模板参数中获得值。[……]

从[强调我的]:

指定显式模板参数列表时,模板参数必须与模板参数列表兼容,并且必须产生如下所述的有效函数类型;否则类型扣除失败。具体而言,在针对给定函数模板计算显式指定的模板参数列表时,将执行以下步骤:

  • (2.1)指定的模板参数必须与实物模板参数相匹配(即类型、非类型、模板)。除非[…],否则参数的数量不得超过参数的数量
特别强调“被引用””和“指定的t
func(Test<int>{});
func(Test<int, int>{});
// (Ex1)
template<typename T, typename U = T>
struct Test{};

template<typename T>
void func(Test<T>) {}

int main() {
    func(Test<int, double>{});
}
// (Ex2)
struct Foo {};
template<typename T> struct Test {};
template<typename T> void f(T) {}

int main() {
    f<Test<int>>(Test<Foo>{});
}
// (Ex1)

// GCC
error: no matching function for call to 'func(Test<int, double>)'
note:   template argument deduction/substitution failed:
        deduced conflicting types for parameter 'T' ('int' and 'double')

// Clang
error: no matching function for call to 'func'
note: candidate template ignored: deduced 
      conflicting types for parameter 'T' ('int' vs. 'double')
// (Ex2)

// GCC
error: could not convert 'Test<Foo>{}' from 'Test<Foo>' to 'Test<int>'

// Clang
error: no matching function for call to 'f'
note: candidate function template not viable: 
      no known conversion from 'Test<Foo>' to 'Test<int>' for 1st argument
template<typename T, typename U = T>
struct Test{};

template<typename T>
void func(Test<T>) {}

int main() {
    func<int>(Test<int, double>{});
}