- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑以下代码:
#include <iostream>
void f(int) { }
void f(int, short) { }
template<typename... Ts> void g(void (*)(Ts...))
{
std::cout << sizeof...(Ts) << '\n';
}
template<typename T, typename... Ts> void h(void (*)(T, Ts...))
{
std::cout << sizeof...(Ts) << '\n';
}
int main()
{
g(f); // #1
g<int>(f); // #2
h(f); // #3
h<int>(f); // #4
}
main()
正文中的每一行分别地。我的期望是所有四个调用都是不明确的,并且会导致编译器错误。
-Wall -Wextra -pedantic -std=c++14
( -std=c++1y
对于 GCC) - 在所有这些情况下的行为相同,除了错误消息的措辞略有不同; #1
: 编译器错误,带有混淆信息,基本上是 no overload of 'f' matching 'void (*)()'
.什么?无参数声明从何而来? #3
:编译器错误,还有一条令人困惑的消息:couldn't infer template argument 'T'
.在那里可能会失败的所有事情中,推导出 T
的论点将是我期望的最后一个... #2
和 #4
: 编译时没有错误和警告,并选择第一个重载。 #2
情况下如何选择一个而不是另一个。和
#4
?他们俩不是绝配吗?
#1
, #3
和 #4
: 编译器错误,有一条好消息:cannot deduce template argument as function argument is ambiguous
.现在这就是我要说的!但是,等等... #2
: 编译时没有错误和警告,并选择第一个重载。分别尝试两个重载,只有第一个匹配。第二个产生错误:cannot convert argument 1 from 'void (*)(int,short)' to 'void (*)(int)'
.没那么好了。 #2
,这是标准(N4296,C++14 final 后的初稿)在[14.8.1p9]中所说的:
Template argument deduction can extend the sequence of template arguments corresponding to a template parameter pack, even when the sequence contains explicitly specified template arguments.
#2
的第一个重载.
最佳答案
据我所知,根据标准,Clang 和 GCC 在所有四种情况下都是正确的,尽管它们的行为可能看起来违反直觉,尤其是在 #2
的情况下。和 #4
.
代码示例中函数调用的分析主要有两个步骤。第一个是模板参数推导和替换。完成后,它会生成一个特化声明( g
或 h
),其中所有模板参数都已替换为实际类型。
然后,第二步尝试匹配 f
的重载针对在上一步中构造的实际函数指针参数。根据[13.4]-重载函数地址中的规则选择最佳匹配;在我们的例子中,这非常简单,因为在重载中没有模板,所以我们要么有一个完美的匹配,要么根本没有。
理解这里发生了什么的关键是第一步中的歧义并不一定意味着整个过程失败。
下面的引用来自 N4296,但内容自 C++11 以来没有改变。
[14.8.2.1p6] 描述了当函数参数是指向函数的指针时模板参数推导的过程(重点是我的):
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
— If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.
The non-deduced contexts are: [...]
— A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:
— more than one function matches the function parameter type (resulting in an ambiguous deduction), or
— no function matches the function parameter type, or
— the set of functions supplied as an argument contains one or more function templates.
[...] A trailing template parameter pack (14.5.3) not otherwise deduced will be deduced to an empty sequence of template arguments. [...]
#1
: 自 Ts
为空序列,g
的参数的专业确实是void (*)()
在这种情况下。然后编译器尝试将重载之一与目标类型匹配并失败。 #3
:T
只出现在非推导的上下文中并且没有明确指定(并且它不是参数包,所以它不能是“空的”),所以不能为 h
构造特化声明,因此消息。 #2
:Ts
无法推导出,但明确指定了一个模板参数,所以 Ts
是 int
, 制作 g
的特化参数void (*)(int)
.然后将重载与此目标类型进行匹配,并选择第一个。 #4
:T
明确指定为 int
和 Ts
是空序列,所以 h
的特化参数是void (*)(int)
,同上。 void f() { }
#1
编译,这与上述所有内容一致。
#1
。 , 对
#3
有点帮助但不是很有帮助,对于
#4
不正确.此外,它对
#2
的行为正如问题中所解释的那样,是其实现中的一个单独问题的副作用;如果不是这样,它可能会为
#2
发出相同的错误消息。以及。
#1
的错误消息和
#3
;我认为他们至少应该包括一个关于非推断上下文及其发生原因的注释。
关于c++ - 可变参数函数指针参数的模板参数推导 - 处理不明确的情况,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29417534/
我刚接触 C 语言几周,所以对它还很陌生。 我见过这样的事情 * (variable-name) = -* (variable-name) 在讲义中,但它到底会做什么?它会否定所指向的值吗? 最佳答案
我有一个指向内存地址的void 指针。然后,我做 int 指针 = void 指针 float 指针 = void 指针 然后,取消引用它们以获取值。 { int x = 25; vo
我正在与计算机控制的泵进行一些串行端口通信,我用来通信的 createfile 函数需要将 com 端口名称解析为 wchar_t 指针。 我也在使用 QT 创建一个表单并获取 com 端口名称作为
#include "stdio.h" #include "malloc.h" int main() { char*x=(char*)malloc(1024); *(x+2)=3; --
#include #include main() { int an_int; void *void_pointer = &an_int; double *double_ptr = void
对于每个时间步长,我都有一个二维矩阵 a[ix][iz],ix 从 0 到 nx-1 和 iz 从 0 到 nz-1。 为了组装所有时间步长的矩阵,我定义了一个长度为 nx*nz*nt 的 3D 指针
我有一个函数,它接受一个指向 char ** 的指针并用字符串填充它(我猜是一个字符串数组)。 *list_of_strings* 在函数内部分配内存。 char * *list_of_strings
我试图了解当涉及到字符和字符串时,内存分配是如何工作的。 我知道声明的数组的名称就像指向数组第一个元素的指针,但该数组将驻留在内存的堆栈中。 另一方面,当我们想要使用内存堆时,我们使用 malloc,
我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。 typedef struct { char *snsAccessID; char *
我得到了以下数组: let arr = [ { children: [ { children: [], current: tru
#include int main(void) { int i; int *ptr = (int *) malloc(5 * sizeof(int)); for (i=0;
我正在编写一个程序,它接受一个三位数整数并将其分成两个整数。 224 将变为 220 和 4。 114 将变为 110 和 4。 基本上,您可以使用模数来完成。我写了我认为应该工作的东西,编译器一直说
好吧,我对 C++ 很陌生,我确定这个问题已经在某个地方得到了回答,而且也很简单,但我似乎找不到答案.... 我有一个自定义数组类,我将其用作练习来尝试了解其工作原理,其定义如下: 标题: class
1) this 指针与其他指针有何不同?据我了解,指针指向堆中的内存。如果有指向它们的指针,这是否意味着对象总是在堆中构造? 2)我们可以在 move 构造函数或 move 赋值中窃取this指针吗?
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: C : pointer to struct in the struct definition 在我的初学者类
我有两个指向指针的结构指针 typedef struct Square { ... ... }Square; Square **s1; //Representing 2D array of say,
变量在内存中是如何定位的?我有这个代码 int w=1; int x=1; int y=1; int z=1; int main(int argc, char** argv) { printf
#include #include main() { char *q[]={"black","white","red"}; printf("%s",*q+3); getch()
我在“C”类中有以下函数 class C { template void Func1(int x); template void Func2(int x); }; template void
我在64位linux下使用c++,编译器(g++)也是64位的。当我打印某个变量的地址时,例如一个整数,它应该打印一个 64 位整数,但实际上它打印了一个 48 位整数。 int i; cout <<
我是一名优秀的程序员,十分优秀!