- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我可以这样做:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(8);
}
};
Boo(8);
return 0;
}
这会编译得很好,我的计数器结果是 21。但是,当我尝试创建传递构造函数参数而不是整数文字的 Boo
对象时,出现编译错误:
#include <iostream>
int counter;
int main()
{
struct Boo
{
Boo(int num)
{
++counter;
if (rand() % num < 7) Boo(num); // No default constructor
// exists for Boo
}
};
Boo(8);
return 0;
}
如何在第二个示例中调用默认构造函数,但在第一个示例中没有调用?这是我在 Visual Studio 2017 上遇到的错误。
在在线 C++ 编译器 onlineGDB 上出现错误:
error: no matching function for call to ‘main()::Boo::Boo()’
if (rand() % num < 7) Boo(num);
^
note: candidate expects 1 argument, 0 provided
最佳答案
Clang 给出了这个警告信息:
<source>:12:16: warning: parentheses were disambiguated as redundant parentheses around declaration of variable named 'num' [-Wvexing-parse]
Boo(num); // No default constructor
^~~~~
这是一个最令人头疼的解析问题。因为 Boo
是类类型的名称,而 num
不是类型名称,所以 Boo(num);
可以是Boo
类型的临时变量,其中 num
是 Boo
的构造函数的参数,或者它可以是声明 Boo num;
在声明符 num
周围有额外的括号(声明符可能总是有)。如果两者都是有效的解释,则标准要求编译器假设声明。
如果它被解析为声明,那么 Boo num;
将调用默认构造函数(没有参数的构造函数),它不是由您声明或隐式声明的(因为您声明了另一个构造函数)。因此程序是非良构的。
这不是Boo(8);
的问题,因为8
不能是变量的标识符(declarator-id),所以被解析为调用创建一个 Boo
临时的 8
作为构造函数的参数,因此不会调用默认构造函数(未声明),而是您手动定义的构造函数。
您可以通过使用 Boo{num};
而不是 Boo(num);
来消除声明中的歧义(因为 {}
不允许在声明符周围),通过使临时变量成为命名变量,例如Boo temp(num);
,或将其作为操作数放在另一个表达式中,例如(Boo(num));
、(void)Boo(num);
等
请注意,如果默认构造函数可用,则声明将是格式良好的,因为它位于 if
的分支 block 范围内,而不是函数的 block 范围内,并且会简单地隐藏 num
在函数的参数列表中。
在任何情况下,将临时对象创建用于应该是正常(成员)函数调用的东西似乎都不是一个好主意。
这种特殊类型的括号中只有一个非类型名称的最麻烦的解析只会发生,因为意图是创建一个临时的并立即丢弃它,或者如果打算创建一个直接用作临时的临时初始化器,例如Boo boo(Boo(num));
(实际上声明函数 boo
接受一个名为 num
的参数,类型为 Boo
并返回 Boo
)。
通常不打算立即丢弃临时对象,并且可以使用大括号初始化或双括号(Boo boo{Boo(num)}
、Boo boo(Boo{ num})
或 Boo boo((Boo(num)));
,但不是 Boo boo(Boo((num)));
)。
如果 Boo
不是类型名称,则它不可能是声明并且不会出现问题。
我还想强调 Boo(8);
正在创建一个 Boo
类型的新临时对象,即使在类作用域和构造函数定义中也是如此。正如人们可能错误地认为的那样,它不像通常的非静态成员函数那样使用调用者的 this
指针调用构造函数。在构造函数体内不能以这种方式调用另一个构造函数。这只能在构造函数的成员初始化器列表中实现。
即使声明由于缺少构造函数而格式错误,也会发生这种情况,因为 [stmt.ambig]/3 :
The disambiguation is purely syntactic; that is, the meaning of the names occurring in such a statement, beyond whether they are type-names or not, is not generally used in or changed by the disambiguation.
[...]
Disambiguation precedes parsing, and a statement disambiguated as a declaration may be an ill-formed declaration.
在编辑中修复:我忽略了有问题的声明与函数参数在不同的范围内,因此如果构造函数可用,则声明格式正确。在任何情况下,在消歧过程中都不会考虑这一点。还扩展了一些细节。
关于c++ - 为什么没有默认构造函数就不能编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53806896/
谁能解释一下原因: (define a (lambda() (cons a #f))) (car (a)) ==> procedure ((car (a))) ==> (procedure . #f)
这是 PyBrain 网站的摘录。我了解大部分正在发生的事情,但是一行让我完全难住了。我以前从未在 python 代码中看到过这样的东西。这是整个循环,对于上下文: for c in [0,
我是gradle / groovy的新手。我想创建将做一些事情的自定义任务。我的第一个问题是任务完成时该如何做?我可以覆盖doFirst / doLast闭包吗?也许我可以重写某些在开始和结束时都会执
我刚刚开始评估 MS 企业库。他们使用以下指令来获取实例: var customerDb = EnterpriseLibraryContainer.Current.GetInstance("C
这是我的 if else Ansible 逻辑.. - name: Check certs exist stat: path=/etc/letsencrypt/live/{{ rootDomain
我正在使用construct 2.8 对一些失传已久的 Pascal 程序创建的一些文件的 header 进行逆向工程。 header 由许多不同的记录组成,其中一些是可选的,我不确定顺序是否固定。
我在将 getchar() 的输入放入 char *arr[] 数组时遇到问题。我这样做的原因是因为输入数据(将是一个带有命令行参数的文件)将存储在一个 char 指针数组中以传递给 execvp 函
通常我们不能约束类型参数 T派生自密封类型(例如 struct 类型)。这将毫无意义,因为只有一种类型适合,因此不需要泛型。所以约束如下: where T : string 或: where T :
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve th
#include using namespace std; class A { private: int m_i; friend int main(int argc, char cons
这个问题在这里已经有了答案: Are there legitimate uses for JavaScript's "with" statement? (33 个答案) 关闭 9 年前。 我有这个代
在this answer我看到了下一个 Bash 结构。 yes "$(< file.txt)" 什么意思 "$(< file.txt)" ? 我明白了 命令替换 - $(command)用命令的结
if (a == 1) //do something else if (a == 2) //do something else if (a == 3) //do somethi
关于构造的快速简单的问题。 我有以下用于将项目添加到 ListView 的代码。 ListViewItem item = new ListViewItem(); item.Text = file; i
我想使用 std::vector 来控制给定的内存。首先,我很确定这不是好的做法,但好奇心占了上风,无论如何我都想知道如何做到这一点。 我遇到的问题是这样的方法: vector getRow(unsi
下面显示了一段简单的javascript: var mystring = ("random","ignored","text","h") + ("ello world") 这个字符串会生成 hello
在 Java 中,创建对象的标准方法是使用 MyClass name = new MyClass(); 我也经常看到构造 new MyClass() { /*stuff goes in here*/
我正在编写 C++ ndarray 类。我需要动态大小和编译时大小已知的数组(分别分配自由存储和分配堆栈)。我想支持从嵌套的 std::initializer_list 进行初始化。 动态大小的没问题
我正在将一个项目从 Visual Studio 2005 转换为 Visual Studio 2008,并提出了上述结构。 using Castle.Core.Resource; using Cast
我想知道我在这里的想法是否正确,我主要针对接口(interface)进行编程,所以我想知道下面的类是否应该通过 DI 注入(inject),或者我应该自己实例化一个类... 注意:这些服务保存在我的核
我是一名优秀的程序员,十分优秀!