我知道 ODR、链接、static和如何extern "C"与函数配合使用。但我不确定类型的可见性,因为它们无法声明static,并且 C 中没有匿名名称空间。
特别是,我想知道以下代码如果编译为 C 和 C++ 的有效性
// A.{c,cpp}
typedef struct foo_t{
int x;
int y;
} Foo;
static int use_foo()
{
Foo f;
f.x=5;
return f.x;
}
Run Code Online (Sandbox Code Playgroud)
// B.{c,cpp}
typedef struct foo_t{
double x;
} Foo;
static int use_foo()
{
Foo f;
f.x=5.0;
return f.x;// Cast on purpose
}
Run Code Online (Sandbox Code Playgroud)
使用以下两个命令(我知道两个编译器都会根据扩展自动检测语言,因此名称不同)。
g++ -std=c++17 -pedantic -Wall -Wextra a.cpp b.cppgcc -std=c11 -pedantic -Wall -Wextra a.c b.c8.3 版本可以愉快地编译两者,没有任何错误。显然,如果两个结构符号都具有外部链接,则存在 ODR 违规,因为定义不相同。是的,编译器不需要报告它,因此我的问题是因为两者都没有报告。
以下代码不能在 C++20 中编译
#include <iostream>
#include <cstddef>
int main(){
std::byte b {65};
std::cout<<"byte: "<<b<<'\n';// Missing overload
}
Run Code Online (Sandbox Code Playgroud)
std::byteC++17什么时候加入的,为什么没有对应的operator<<重载打印呢?我也许可以理解不打印容器的选择,但为什么不std::byte呢?它试图充当原始类型,我们甚至有 的重载std::string,最近的std::string_view,也许是最相关的 std::complex,并且std::bitset它本身可以被打印。
还有std::hex类似的修饰符,所以默认打印 0-255 应该不是问题。
这只是疏忽吗?怎么样operator>>,std::bitset有它,它根本不是微不足道的。
编辑:发现甚至std::bitset可以打印。
我知道在编译时复制任意内存块并不总是可能的,但既然我们得到了 constexpr 容器、虚拟方法和算法,为什么不也复制 memcpy 呢?这也是一种算法。
\n此外,
\nstd::bit_cast看起来很像std::memcpy解决方法reinterpret_cast,但它确实是constexpr。std::copy使用迭代器被标记为constexprC++20,因此对于类型来说复制是可能的。用法是复制或只是“重新解释”constexpr函数中的变量/数组,据我所知,前者没有解决std::bit_cast。特别是这个问题和我的答案想用它。
std::bit_cast可以是 constexpr 而std::memcpy不能是有什么特殊原因吗?std::bit_cast和 中的迭代器std::copy。C++20 bit_cast vs reinterpret_cast的相关答案简要引用于某处:
\n\n此外,目前不可能实现 constexpr\n位转换函数,因为 memcpy 本身不是 \xe2\x80\x99t constexpr。将提议的函数标记为 constexpr 不需要或阻止 memcpy 变成 …
Originally, I presented a more complicated example, this one was proposed by @n. 'pronouns' m. in a now-deleted answer. But the question became too long, see edit history if you are interested.
Has the following program well-defined behaviour in C++17?
int main()
{
int a=5;
(a += 1) += a;
return a;
}
Run Code Online (Sandbox Code Playgroud)
I believe this expression is well-defined and evaluated like this:
a is evaluated to 5.假设我们要创建一个只能用数字实例化的模板类,否则就不应该编译。我的尝试:
#include <type_traits>
template<typename T, typename = void>
struct OnlyNumbers{
public:
struct C{};
static_assert(std::is_same<C,T>::value, "T is not arithmetic type.");
//OnlyNumbers<C>* ptr;
};
template<typename T>
struct OnlyNumbers<T, std::enable_if_t<std::is_arithmetic_v<T>>>{};
struct Foo{};
int main()
{
OnlyNumbers<int>{}; //Compiles
//OnlyNumbers<Foo>{}; //Error
}
Run Code Online (Sandbox Code Playgroud)
现场演示 -所有三个主要的编译器似乎都能按预期工作。我知道已经有一个类似的问题,答案引用了该标准。接受的答案使用temp.res.8和temp.dep.1来回答该问题。我认为我的问题有所不同,因为我只是在问我的示例,我不确定标准对此的看法。
我认为我的程序不是格式错误的,并且仅当编译器尝试实例化基本模板时,它才应该无法编译。我的推理:
[temp.dep.1]:
在模板内部,某些构造的语义可能因一个实例而异。这样的构造取决于模板参数。
这应该使std::is_same<C,T>::value依赖T。
[temp.res.8.1]:
如果模板中的语句或模板未实例化,则无法为模板或constexpr的子语句生成有效的专业化名称;或者
不适用,因为存在有效的专业化,尤其OnlyNumbers<C>是有效的,并且可以在类内部用于例如定义成员指针variable(ptr)。实际上,通过删除断言并取消注释ptr,OnlyNumbers<Foo>代码行得以编译。
[temp.res.8.2-8.4]不适用。
我的问题是:我的推理正确吗?这是一种使特定[class] *模板static_assert仅在实例化时无法编译的安全,符合标准的方法吗?
*基本上,我对类模板感兴趣,请随时包含函数模板。但是我认为规则是相同的。
**这意味着没有T像T=C从内部使用那样可以从外部实例化模板。即使C可以通过某种方式访问,我也不认为有一种方法可以引用它,因为它会导致这种递归OnlyNumbers<OnlyNumbers<...>::C> …
有多个问题询问mmap和访问共享内存中的结构,同时不通过违反严格的别名规则或违反对象生存期来调用 UB。
一致认为,如果不复制数据,这通常是不可能的。
\n更一般地说,多年来,我看到了无数涉及reinterpret_cast(或更糟)序列化(反序列化)的代码片段,违反了这些规则。我总是建议std::memcpy,同时声称编译器将删除这些副本。我们现在可以做得更好吗?
我想澄清简单地将一堆字节解释为另一种 POD 类型 w\xcc\xb2i\xcc\xb2t\xcc\xb2h\xcc\xb2o\xcc\xb2u\xcc\xb2t\xcc\xb2 的正确方法是什么在 C++20 中复制数据?
\n据我所知,有一个提案P0593R6已被 C++20 接受。
\n根据阅读内容,我相信以下代码是安全的:
\ntemplate <class T>\nT* pune(void* ptr) {\n // Guaranteed O(1) initialization without overwritting the data.\n auto* dest = new (ptr) std::byte[sizeof(T)];\n // There is an implicitly created T, so cast is valid.\n return reinterpret_cast<T*>(dest);\n}\nRun Code Online (Sandbox Code Playgroud)\n#include <cstring>\n#include <array>\n#include <fmt/core.h>\n\nstruct …Run Code Online (Sandbox Code Playgroud) 假设我有两个进程,它们都使用shm_open和共享一个内存块,mmap并且存在一个共享同步原语 - 假设是一个信号量 - 确保对内存的独占访问。即没有竞争条件。
我的理解是,从返回的指针mmap仍必须标记为 volatile 以防止缓存读取。
现在,如何将例如 a 写入std::uint64_t内存中的任何对齐位置?
当然,我会简单地使用std::memcpy但它不适用于指向易失性内存的指针。
// Pointer to the shared memory, assume it is aligned correctly.
volatile unsigned char* ptr;
// Value to store, initialize "randomly" to prevent compiler
// optimization, for testing purposes.
std::uint64_t value = *reinterpret_cast<volatile std::uint64_t*>(nullptr);
// Store byte-by-byte
unsigned char* src = reinterpret_cast<unsigned char*>(&value);
for(std::size_t i=0;i<sizeof(value);++i)
ptr[i]=src[i];
Run Code Online (Sandbox Code Playgroud)
神箭。
我坚信这个解决方案是正确的,但即使使用-O3,也有 8 个 1 字节传输。这真的不是最优的。
因为我知道在我锁定内存时没有人会更改内存,所以也许 …
我想做一个通用的包装函数,它可以接受任何
*this)包括重载或模板化的情况以及可变参数。然后,这样的包装器将在主体中准确地使用转发的参数调用该函数。
示例:
template<typename Fnc,typename...Args>
void wrapper(Fnc fnc, Args&&...args){
// Do some stuff
// Please disregard the case when return type is void,
// that be SFINAED with std::result_of.
auto res = fnc(std::forward<Args>(args)...);
// Do some stuff
return res;
}
Run Code Online (Sandbox Code Playgroud)
#include <vector>
auto foo(int i){ return i; }
auto foo(double& d){ return d; }
auto foo(double&& d){ return d; }
auto foo(const char* str){ return str; }
template<typename...T>
auto generic_foo(T&&...ts){/* ...*/ return /* ...*/; …Run Code Online (Sandbox Code Playgroud)