在这个网站上有以下段落(强调我的):
- 自动存储时间.在输入声明对象的块时分配存储,并在通过任何方式退出时取消分配(转到,返回,到达结尾).一个例外是VLA; 它们的存储在执行声明时分配,而不是在块条目上分配,并在声明超出范围时分配,而不是在退出块时分配(自C99起).如果以递归方式输入块,则对每个递归级别执行新的分配.所有函数参数和非静态块作用域对象都具有此存储持续时间,以及块作用域中使用的复合文字.
超出范围的声明与退出的块之间有什么区别?你能提供一个例子吗?
在此网站上,指定:
"constexpr功能必须满足以下要求:
[...]
存在至少一组参数值,使得函数的调用可以是核心常量表达式的计算子表达式(对于构造函数,在常量初始化器中使用就足够了)(自C++ 14起).违反此子弹无需诊断."
粗体陈述的含义是什么?
我正在阅读这个答案,其中有以下示例:
struct R {};
struct S { S(R); };
struct T {
T(const T &); //1
T(S); //2
};
void f(T);
void g(R r) {
f({r});
}
Run Code Online (Sandbox Code Playgroud)
答案与[over.best.ics]/4的旧版本有关,当时看起来像这样:
但是,当考虑构造函数或用户定义的转换函数的参数时,[over.match.ctor]在类复制初始化的第二步中为复制/移动临时函数而调用时,通过[ over.match.list]当将初始化列表作为单个参数传递时,或者当初始化列表只有一个元素并且转换为某个类X或引用(可能是cv-qualified)时,X被认为是构造函数的第一个参数X的,或通过[over.match.copy],[over.match.conv]或[over.match.ref]在所有情况下,唯一的标准转换序列和省略号转换序列被考虑.
在答案中,据说没有上面引用中突出显示的部分,f({r})将是不明确的,因为它可以使用T(1)的第一个构造函数或第二个构造函数(2).
但是,尽管我尝试过,但我看不出第一个构造函数(1)是如何选择的.f({r})导致副本列表初始化的T距离{r}.如果使用第一个构造函数,则标准允许从r构造函数的参数类型转换.但是,只有一次转换是不够的,因为必须使用R - > S(使用转换构造函数S)然后S - > T(使用T(2)的转换构造函数).我在标准中找不到任何允许在列表初始化的转换中进行多个用户定义转换的内容.
我可能会遗漏一些东西.如果有人指出我错在哪里,或者我不是,我会很感激,我想知道标准引用中突出显示部分的目的是什么.
引用段落的当前版本要求初始化列表的唯一元素是初始化列表本身,这在上面的示例中是有意义的,如果不是这样的f({r})话f({{r}}).在这种情况下,解释是正确的.
谢谢.
在当前版本的C ++标准草案中,[basic.life] / 1 指出:
对象或引用的生存期是对象或引用的运行时属性。如果变量是默认初始化的,则被称为具有空虚的初始化;如果变量是类类型或其(可能是多维的)数组,则该类类型具有琐碎的默认构造函数。类型为T的对象的生存期始于以下情况:
获得具有适合T型的对齐方式和大小的存储,并且
它的初始化(如果有的话)已经完成(包括真空初始化)([dcl.init]),
除了对象是联合成员或其子对象的情况外,其生存期仅在该联合成员是联合中的初始化成员([dcl.init.aggr],[class.base.init])或按照[class.union]。[...]
从该段我知道,工会会员开始其存在的唯一途径是:
mem-initializer),或者然而,唯一的规范在[class.union]段落指定一个联合成员如何开始其生命周期是[class.union] / 5(但它仅适用于特定类型的,即,或者non-class,non-array或class类型与trivial构造是未删除或此类数组)。
下一个段落[class.union] / 6(包含一个注释和一个示例,因此不包含规范性文本)描述了一种通过使用placement new-expression,例如来更改联合的活动成员的方法new (&u.n) N;,其中
struct N { N() { /* non-trivial constructor */ } };
struct M { M() { /* non-trivial constructor */ } };
union
{
N n;
M m;
} u;
Run Code Online (Sandbox Code Playgroud)
我的问题是在标准中指定new (&u.n) N;从哪里开始的生命周期 …
在当前 (C++ 17) C++ 标准草案的 [intro.execution] 的第 12 段中写道:
一个完整的表达式是:
[...]
- 不是另一个表达式的子表达式并且不是完整表达式的一部分的表达式。
如果语言构造被定义为产生函数的隐式调用,则出于此定义的目的,语言构造的使用被认为是表达式。[...]
“使用语言构造”的措辞是指构造本身被视为表达式,还是构造“使用”的隐式调用将被视为表达式?
我问这个是因为在同一段中有这个代码示例:
S s1(1); // full-expression is call of S?::?S(int)
Run Code Online (Sandbox Code Playgroud)
该评论将表明第二种解释是正确的。
但是,该段落明确指出init-declarator是full-expression,这表明注释是错误的。
在过去(我相信甚至在 C++03 之前),这一段看起来是这样的(取自这个缺陷报告):
完整表达式是不是另一个表达式的子表达式的表达式。如果语言构造被定义为产生函数的隐式调用,则出于此定义的目的,语言构造的使用被认为是表达式。
[注意:C++ 中的某些上下文会导致对由表达式(5.19 [expr.comma])以外的句法构造产生的完整表达式进行评估。例如,在 8.6 [dcl.init] 中,初始化程序的一种语法是
( 表达式列表 )
但生成的构造是对构造函数的函数调用,并将表达式列表作为参数列表;这样的函数调用是一个完整的表达式。例如,在 8.6 [dcl.init] 中,初始化程序的另一种语法是
= 初始化子句
但同样,结果构造可能是对构造函数的函数调用,并以一个赋值表达式作为参数;同样,函数调用是一个完整的表达式。]
这是相信第二种解释就是预期的另一个原因。
我知道这对语言的理解没有影响,但我只想知道最初写这一段的人的意图是什么。
在C ++标准的最新草案(2019年3月)中[class.friend] p.6声明(重点是我):
仅当该类是非本地类([class.local]),函数名称不合格且该函数具有名称空间作用域时,才可以在该类的朋友声明中定义一个函数。[...]
“该函数具有名称空间范围”是什么意思?
在这种情况下,函数没有命名空间范围的唯一情况是:
struct A
{
static void f();
struct B
{
friend void f() {};
};
};
Run Code Online (Sandbox Code Playgroud)
但是,clang和gcc都不会将内部的friend定义与内部B的static方法关联A,而是与属于全局名称空间的函数关联。
还有其他情况我想念吗?
考虑到这段代码:
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
Run Code Online (Sandbox Code Playgroud)
诸如此类的调用int *p; f(p);将输出First.
如果声明的顺序改变了,像这样:
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <> …Run Code Online (Sandbox Code Playgroud) 我正在阅读这个 stackoverflow 答案const T&&,其中给出了不是通用(转发)参考的一个原因:
允许 const T&& 充当转发引用,将无法重载仅采用右值引用作为参数的模板函数。
我不知道这是什么意思。我想这意味着同一个函数(模板)有两个重载,其中一个重载作为参数const T&&。我还假设这些重载之一将始终被调用,而另一个永远不会被调用。
如果我的假设是正确的,那么这两个重载函数是什么?或者如果我错了,引用的段落实际上是什么意思?
谢谢。
$<TARGET_NAME:...>标记
...为目标名称。如果将目标导出到多个从属导出集,则这是必需的。的...必须是它可能不包含发电机表达式靶的文字名称。
我试图理解突出显示的部分。
首先,我想看看我是否正确理解了依赖导出集的概念。如果目标B取决于目标A,并且导出集 EXP_A包含目标,A而导出集 EXP_B包含目标B,则导出集 EXP_B取决于导出集 EXP_A。它是否正确?
为什么$<TARGET_NAME:...>“ 如果将目标导出到多个从属导出集是必需的 ”?
谢谢。
缺陷报告 115 ( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#115 ) 表示,如果 template-id 标识单个函数模板专业化,则它被认为是该函数模板特化的左值,如果模板参数推导(我想是针对由 template-id 内的 template-name 命名的函数模板的模板参数)未完成,或者已完成,但失败。
我相信此缺陷报告的目的是允许以下程序:
template <typename Fn>
void f(Fn param);
template <typename T>
void g(T);
int main()
{
f(g<int>);
}
Run Code Online (Sandbox Code Playgroud)
这是因为在 call 中, ( )f(g<int>)的类型是非推导上下文,因为其各自的参数曾经是(在此缺陷报告之前)函数模板。缺陷报告的“在未完成模板参数推导的上下文中”部分涵盖了这一点。paramFn
我难以理解的是为什么缺陷报告还提到了模板参数推导已完成但失败的情况。为什么需要在缺陷报告中明确提及这些背景?这些情况在 [temp.arg.explicit] p 中都明确提到。4和[over.over] p。2 .
我想出了一个示例,该示例可能包含在缺陷报告的“完成模板参数推导但失败的上下文”部分中,但是我非常怀疑这就是这部分被添加到缺陷报告中的原因。示例如下所示:
template <int i>
struct B {};
template <short i = 0>
void f(B<i>);
int main()
{
void (*pf) (B<0> param);
pf = f<>();
}
Run Code Online (Sandbox Code Playgroud)
i在上面的例子中,模板实参推导失败是因为函数模板的非类型模板参数的f类型是
short,而类模板的非类型模板参数i的 …