一个typedef
函数可以使用类型,即使使用类cv-和ref限定符也可以:
typedef void F() const volatile &&;
Run Code Online (Sandbox Code Playgroud)
这可以用于声明(但不能定义)非静态成员函数:
struct A {
F f; // void f() const volatile &&
};
Run Code Online (Sandbox Code Playgroud)
F
在模板的依赖上下文中明确禁止使用此功能。
它也可以用作模板参数。据我所知,但是没有办法提取或处理该类型的cv和ref限定词。
是否还有其他用例typedef
(使用任何限定符,不一定一次全部使用)?
C ++标准未指定临时对象的存储期限。这是CWG第1634期的主题。
根据链接的网站,此问题的状态为“草稿”,表示:
起草:尽管尚无确切的措辞,但工作组已达成非正式共识,并在暂定决议中对此进行了粗略的描述。
但是,没有明确提及针对该特定问题的共识/解决方案,我也无法在委员会站点上的其他任何地方找到它。
我猜想,一个共识是,生命周期延长的临时对象的存储期限应等于它们所绑定的参考的存储期限,但是对于非生命周期延长的临时人员而言,尚不清楚。
特别是对我来说,目前尚不清楚在块范围内的语句中创建的临时变量是否具有(自动?)存储持续时间扩展到块末尾(如在同一点声明的自动变量一样),或者是否具有存储持续时间在全表达式结束时以其(默认)生存期结束。问题说明暗示了后者的情况。
说明中是否应该包含“ 暂定解决方案 ”,如果我解释正确或不正确,是否可以在其他地方找到该问题的“ 暂定解决方案 ”?
In addition, do the major compilers currently follow this consensus, either in a documented manner or de-facto?
See also older questions:
Edit for clarification:
I am not asking about the lifetime of the temporary, that is well-specified in the …
C++17 标准(最终草案)的[temp.arg.explicit]/3说明了使用明确指定的模板参数列表来推导函数模板参数:
在推导完成但失败或 [...] 的上下文中,如果指定了模板参数列表,并且它与任何默认模板参数一起标识单个函数模板特化,则模板 ID 是函数模板特化。
这如何应用于参数包?
考虑
template<typename...>
struct S {
S(int) {}
};
template<typename... A>
void f(S<A...>) {}
int main() {
f<int>(0);
}
Run Code Online (Sandbox Code Playgroud)
这在 MSVC 上编译,但不在 GCC 和 Clang 上编译,请参阅Godbolt。这也是我的直觉,它应该失败,因为演绎会失败,但上面的引用似乎暗示即使演绎失败,因为f<int>
(在我的理解中)唯一标识了一个模板专业化,f<int>
应该被认为是指那个专业化和然后调用它,没有重载决议,这将起作用,隐式转换0
为S<int>
.
我对引用的理解有什么问题,还是 MSVC 确实正确?
请注意,如果我们尝试调用f<>(0);
(我猜应该通过上述考虑可以工作)所有三个编译器都拒绝编译。
成员函数指针不能是reinterpret_cast
函数指针。(不过,GCC需要该-pedantic-errors
标志来强制执行该操作。)
但是,GCC,Clang和MSVC似乎同意将成员函数指针转换为对函数指针的引用是可以的。请参见以下示例:
#include<type_traits>
struct A {
void f() {}
};
int main() {
auto x = &A::f;
auto y = reinterpret_cast<void(*&)()>(x);
// auto y = reinterpret_cast<void(*)()>(x);
static_assert(std::is_same_v<decltype(y), void(*)()>);
}
Run Code Online (Sandbox Code Playgroud)
该程序可以在所有三个编译器上编译,但是当使用注释掉的行而不是前一个注释行时,所有程序(带有pedantic标志)都无法编译。
我在标准中看不到任何允许这种转换的规则。程序格式错误,编译器无法对其进行诊断还是程序格式正确?
如果是后者,那么确切的转换顺序是什么,标准在哪里允许它,并且可以将函数指针转换回原始类型以便调用它,还是使用引用来初始化y
已经不确定的行为?
c++ member-function-pointers function-pointers language-lawyer reinterpret-cast
ABI 标准中与内存布局相关的规范是否通常仅适用于 ABI 边界或例如在翻译单元内,或者如果不是这种情况,编译器通常是否会做出此类额外保证?
如果“一般”太宽泛,请考虑例如带有 System V x64 和 Itanium C++ ABI 的 GCC/Clang。
这里有两个例子来说明我的意思:
System V x64 ABI 指定大小至少为 16 字节的数组具有至少 16 字节的对齐,即使元素类型的对齐更小,因此对齐比alignof
建议的更严格。它还指定 的对齐方式long double
是16
。那么以下在 C++ 标准下具有未定义行为的函数(如果调用)是否可以安全地在 System V x86 ABI 下使用,即使该storage
数组从未跨翻译单元边界公开?
void f() {
char storage[16]; // Only guaranteed to have alignment `1` by the C++ standard.
using T = long double;
auto p = new(storage) T;
}
Run Code Online (Sandbox Code Playgroud)Itanium C++ ABI 指定了类的布局。例如:
#include<new>
struct A {
int i;
virtual ~A() …
Run Code Online (Sandbox Code Playgroud)C++17(草案 N4659)[basic.compound]/3说:
指针类型的每个值都是以下之一:
指向对象或函数的指针(该指针被称为指向该对象或函数),或
超过对象末尾的指针 ([expr.add]),或
该类型的空指针值 ([conv.ptr]),或
无效的指针值。
这些类别中的哪一个属于指向对象生命周期之外已分配内存的指针,特别是以下程序中a
at // (1)
through// (3)
和b
at的值// (4)
?
#include<new>
#include<algorithm>
struct S {
~S() { /* Non-trivial destructor */ }
};
struct T {
~T() { /* Non-trivial destructor */ }
};
int main() {
void* a = operator new(std::max(sizeof(S), sizeof(T)));
// (1)
a = new(a) S;
static_cast<S*>(a)->~S();
// (2)
a = new(a) T;
static_cast<T*>(a)->~T();
// (3)
operator delete(a);
void* b = operator …
Run Code Online (Sandbox Code Playgroud) 在下面的示例中,是否有必要在源文件中使用名称空间A {}还是因为它已经在头文件中完成而具有冗余性?
// header file Foo.h
namespace A
{
class Foo
{
Foo();
};
}
// source file Foo.cpp
#include "Foo.h"
namespace A
{
Foo::Foo() {}
}
Run Code Online (Sandbox Code Playgroud) #include <iostream>
using namespace std;
void aa(int n) {
int test[n] = {0};
}
int main() {
aa(10);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并得到
error: variable-sized object may not be initialized
Run Code Online (Sandbox Code Playgroud)
但
#include <iostream>
using namespace std;
void aa(int n) {
int test[n];
fill(test,test+10,0);
}
int main() {
aa(10);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
还可以
我想知道为什么在前一个失败的情况下编译该文件的原因。
考虑以下三个程序:
// program 1
#include<new>
struct A {
const int a = 0;
int b = 0;
};
int main() {
auto a = new A[2];
new(a+1) A;
a[1].b = 1;
}
Run Code Online (Sandbox Code Playgroud)
// program 2
#include<new>
struct A {
const int a = 0;
int b = 0;
};
int main() {
auto a = new A[2];
new(a) A;
a[0].b = 1;
}
Run Code Online (Sandbox Code Playgroud)
// program 3
#include<new>
struct A {
const int a = 0;
int b = 0;
}; …
Run Code Online (Sandbox Code Playgroud) 我正在尝试通过添加智能指针来现代化一些GStreamer代码。例如:
GstElement *pipeline = gst_pipeline_new("test-pipeline");
gst_object_unref(pipeline);
Run Code Online (Sandbox Code Playgroud)
可以重写:
struct GstElementDeleter {
void operator()(GstElement* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GstElementDeleter> pipeline = gst_pipeline_new("test-pipeline");
Run Code Online (Sandbox Code Playgroud)
但gst_object_unref()
可以用于任何内容gpointer
,因此可以重写:
template<typename T>
struct GPointerDeleter {
void operator()(T* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GPointerDeleter<GstElement>> pipeline = gst_pipeline_new("test-pipeline");
Run Code Online (Sandbox Code Playgroud)
但我想做的是将其限制为仅处理可以使用gst_object_unref
. 有没有一种方法可以声明模板仅适用于类型列表 - GstElement
、GstBus
等?
c++ ×10
c++17 ×2
abi ×1
arrays ×1
clang++ ×1
gstreamer ×1
namespaces ×1
pointers ×1
stack ×1
template-argument-deduction ×1
templates ×1
unique-ptr ×1