我想要一个对应于的有符号类型std::size(理想情况下是根据它计算出来的,而不是依赖于另一个可能独立的定义。)自然地,我想到使用std::make_signed_t<std::size_t>.
然而,当我查看时std::ssize,我注意到返回类型是std::common_type_tand std::ptrdiff_t。decltype(c.size())现在c.size()应该是未签名的,但无论哪种情况,它都应该被签名,因为std::ptrdiff_t它是。剩下的就是尺寸了;那应该是两种类型中较大的一个。
我不明白的是为什么你会使用一个大的类型,就像std::ptrdiff_t你想要最大的有符号类型一样。如果它真的是最大的,那就没有意义了std::common_type_t。相反,假设std::common_type_t并不总是返回std::ptrdiff_t,这意味着decltype(c.size())是不同的大小,并且有效地std::ptrdiff_t用于最小大小的有符号类型。如果是这样的话,难道不应该使用最小的有符号类型吗?decltype(c.size())或者说,为什么不直接使用对应的有符号类型呢?该定义背后的意图是什么?
template<template<auto> class> struct A {};
template<int&> struct B {};
A<B> a;
int main() {}
Run Code Online (Sandbox Code Playgroud)
所有三个编译器 MSVC、GCC 和 Clang 的最新版本都接受此代码 ( https://godbolt.org/z/b7Pv7Ybxv )。但是,auto无法推断出引用类型,那么为什么允许这样做呢?或者编译器在查看标准内容时是否错误地接受了它?
我混淆了上面的参数和参数。我的目的是想问
template<template<int&> class> struct A {};
template<auto> struct B {};
A<B> a;
int main() {}
Run Code Online (Sandbox Code Playgroud)
这也被上述所有编译器所接受。然而,最初的示例也很有趣,因为模板模板参数应该至少与模板参数一样专业,但直观上看起来并不如此。
c++ template-templates language-lawyer auto non-type-template-parameter
std::launder有一个先决条件:从将要返回的指针可到达的所有字节都可以通过传递的指针到达。
我的理解是,这是为了允许编译器优化,以便例如
struct A {
int a[2];
int b;
};
void f(int&);
int g() {
A a{{0,0},2};
f(a.a[0]);
return a.b;
}
Run Code Online (Sandbox Code Playgroud)
可以优化为始终返回2。(请参阅指针可互换性与具有相同地址和能否使用 std::launder 将对象指针转换为其封闭数组指针?)
这是否意味着可达性先决条件也应该适用于placement-new?否则有什么阻止我写f如下吗?:
void f(int& x) {
new(&x) A{{0,0},0};
}
Run Code Online (Sandbox Code Playgroud)
的地址与 的地址a.a[0]相同,a并且新A对象可以透明地替换为旧A对象,因此a.bing现在应该是0。
namespace N {
struct A {};
template<typename T>
constexpr bool operator<(const T&, const T&) { return true; }
}
constexpr bool operator<(const N::A&, const N::A&) { return false; }
#include<functional>
int main() {
static_assert(std::less<N::A>{}({}, {}), "assertion failed");
}
Run Code Online (Sandbox Code Playgroud)
请参阅https://godbolt.org/z/vsd3qfch6。
该程序在看似随机的编译器版本上进行编译。
自 v19.15 以来,断言在所有版本的 MSVC 上都失败,但在 v19.14 上成功。
它在 GCC 11.2 及之前版本上成功,但在当前 GCC 主干上失败。
在所有版本中,它在带有 libstdc++ 的 Clang 上都会失败。它在所有版本中都能成功使用 libc++,包括当前的 trunk,版本 13 除外。
ICC 总是能成功。
是否指定是否static_assert应该成功?
这里的根本问题是std::less使用<内部,因为它在模板中使用,它将operator<通过从实例化点(这是正确的方法)进行参数相关的查找来查找重载,而且还通过从定义点进行非限定名称查找来查找重载模板。
如果发现全局重载,则这是一个更好的匹配。不幸的是,这使得程序行为依赖于标准库包含的位置和顺序。
我本以为标准库会禁用std命名空间之外的非限定名称查找,因为无论如何都不能依赖它,但这应该得到保证吗?
CWG 1885的存在似乎意味着在 C++14 之前,以下代码不能保证线程安全
std::string get_string()
{
std::unique_lock<std::mutex> lock(some_shared_mutex);
return some_shared_string;
}
Run Code Online (Sandbox Code Playgroud)
因为函数退出时事件的顺序无法保证 - 例如,lock在要返回的临时对象从 复制初始化之前可能会被销毁some_shared_string,从而导致竞争条件。
这在实践中似乎不太可能成为问题——这是它的主要优点之一unique_lock是你应该能够做这样的事情,我会有点惊讶地发现实现并不能保证即使标准没有这样做。
所以我的问题
我刚刚遇到一个案例,我想声明 C++ 20concept已弃用。然而,我的编译器(Apple Clang 14)似乎不接受[[deprecated]]向concept. 我的尝试看起来像
template <class T>
concept [[deprecated ("Some explanation")]] myConcept = someBoolCondition<T>;
Run Code Online (Sandbox Code Playgroud)
是否根本不支持弃用概念,我是否选择了错误的语法,或者这是我的编译器的缺陷?
If I compile g++ with -Wformat on the following code, I get a warning, as expected.
int main(int argc, char * argv[])
{
printf("argc %lld\n", argc);
}
Run Code Online (Sandbox Code Playgroud)
However, if compile the following code, I get no warning.
template <typename... Ts>
void foo(char const * s, Ts && ... ts)
{
printf(s, std::forward<Ts>(ts)...);
}
int main(int argc, char * argv[])
{
foo("argc %lld\n", argc);
}
Run Code Online (Sandbox Code Playgroud)
I was a bit surprised, but I thought maybe the references were throwing off the detection, …
下面的代码中,为什么POD被认为是POD,而notPOD被认为不是POD呢?它们之间的唯一区别是默认构造函数的定义是放在类内部还是外部。我一直认为两者做同样的事情,但事实显然并非如此。
#include <iostream>
struct POD {
POD() = default;
};
struct notPOD {
notPOD();
};
notPOD::notPOD() = default;
int main() {
std::cout << std::boolalpha << std::is_pod<POD>() << ' ' << std::is_pod<notPOD>() << '\n';
}
Run Code Online (Sandbox Code Playgroud) [intro.compliance.general]/2指定编译器应如何处理给定的程序。
特别是它有两点处理格式错误的程序。(2.2) 要求编译器针对违反可诊断规则的情况发出至少一个诊断。(2.3) 指出,对于违反不需要诊断的规则的程序,没有对编译器强加任何要求。
不幸的是,我认为该段落没有明确说明这两个要求之间的优先级。如果程序包含违反需要诊断的可诊断规则的情况以及违反不需要诊断的规则的情况,编译器是否需要发出诊断?
作为一个例子(被视为一个完整的单翻译单元程序):
// ill-formed, diagnostic required
int main() { using T = void&; }
// IFNDR according to [temp.res.general]/8.1 and [temp.res.general]/8.4
void f(auto) { using T = void&; }
Run Code Online (Sandbox Code Playgroud)
此外,如果 IFNDR 优先,则同样可能适用于通常被视为运行时 UB 的未定义行为,例如
// always runtime undefined behavior
int main() { return *(int*)0; }
// ill-formed, diagnostic required
using T = void&;
Run Code Online (Sandbox Code Playgroud)
那么从技术上讲也不需要诊断(被视为一个完整的单翻译单元程序)?
从实现质量的角度来看,我认为编译器在这种情况下应该尽可能发出诊断。
但我的印象是,该标准实际上并不要求这样做,这也是我之前读到/听到的。例如,[temp.res.general]/8.1中的“并且模板未实例化”的限定否则没有多大意义。然而,在其他时候,标准不使用似乎应该需要的此类反转限定,例如[dcl.constexpr]/6。
在 GCC 和 Clang 中,我们可以将整数变量传递给属性。
constexpr auto SIZE = 16;
int a [[gnu::vector_size(SIZE)]];
Run Code Online (Sandbox Code Playgroud)
当我们编写模板时,这特别有用。
template<size_t N>
struct Vec {
int inner [[gnu::vector_size(N)]];
};
Run Code Online (Sandbox Code Playgroud)
但是,如果该属性需要一个字符串,我找不到使用这样的变量的方法。这两种方法都不起作用。
constexpr const char* TARGET = "default";
[[gnu::target(TARGET)]] void foo() {}
Run Code Online (Sandbox Code Playgroud)
constexpr const char TARGET[] = "default";
[[gnu::target(TARGET)]] void foo() {}
Run Code Online (Sandbox Code Playgroud)
有没有办法实现这一目标?
c++ ×10
c++11 ×2
c++17 ×2
gcc ×2
auto ×1
c++-concepts ×1
c++20 ×1
clang ×1
gcc-warning ×1
name-lookup ×1
non-type-template-parameter ×1
signed ×1
size ×1
std ×1
stdlaunder ×1
types ×1