小编Vai*_*Man的帖子

alignof(T) with T=__m512 不等于 alignof(__m512)

我遇到了一个奇怪的情况,alignof(__m512)它不等于std::alignment_of<__m512>::value由 Apple 的 clang 编译。经过一些测试,我发现当alignof(T)在模板中使用 进行评估时T=__m512,结果与直接不同alignof(__m512)。我还在 ubuntu(WSL) 上运行了几个由 g++ 和非 Apple 的 clang 编译的测试,并得到了正确的(我认为)行为。这是Apple的clang错误还是有关实施行为的问题?

#include <immintrin.h> //avx headers

#include <cstdio>
#include <typeinfo>
#include <type_traits>

void test_directly() {
  printf("directly: typeid %s alignof %zu\n", typeid(__m512).name(), alignof(__m512));
}

template<typename T>
void test_as_template_argument() {
  static_assert(std::is_same<T, __m512>::value, "assert");
  printf("template: typeid %s alignof %zu\n", typeid(T).name(), alignof(T));
}

int main() {
  test_directly();
  test_as_template_argument<__m512>();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出(编译clang++ -std=c++17 -march=native):

directly: typeid Dv16_f alignof 64
template: …
Run Code Online (Sandbox Code Playgroud)

c++ clang++

27
推荐指数
1
解决办法
457
查看次数

为什么参数映射中的替换失败被认为是格式错误的?

此代码中,

template<class T, class U>
concept always_true = true;

template<class T>
concept always_true_if_tagged = always_true<T, typename T::tag>;

struct A {
    using tag = int;
};

static_assert(always_true_if_tagged<A>);
static_assert(!always_true_if_tagged<int>);  //GCC says this failed
Run Code Online (Sandbox Code Playgroud)

GCC 表示第二个断言失败。Clang 和 MSVC 都同意编译它。

我最初认为它是不正确的,不需要诊断,因为temp.constr.normal#1.4

概念 ID 的范式C<A1, A2, ..., An>是 的约束表达式的范式C,在替换A1, A2, ..., An每个C原子约束中的参数映射中的各自模板参数后。如果任何此类替换导致无效类型或表达式,则该程序格式错误;无需诊断。

替换T::typename tag是 的参数映射always_true,因此格式错误;无需诊断。

所以我的前两个问题是

  1. 我说得对吗?(格式是否错误?我是否引用了正确的原因?)
  2. 为什么它应该是格式错误的?(如果我是对的。)

解决方案之一是检查之前的嵌套类型名。所以参数映射always_true不会发生。

template<class T>
concept always_true_if_tagged =
    requires …
Run Code Online (Sandbox Code Playgroud)

c++ language-design language-lawyer c++-concepts c++20

25
推荐指数
1
解决办法
909
查看次数

[[(un)likely]] 属性和 do-while 循环

简而言之:是否有一个地方可以放置属性,[[(un)likely]]以便控制流被cond2认为可能采取错误分支,而不影响分支的可能性cond1

\n
if (cond1) {\n  do {\n    foo();\n  } while (cond2);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果我输入[[unlikely]]or do [[unlikely]] {\ do { [[unlikely]]xef\xbc\x8c ,它会影响\xef\xbc\x9f 因为根据cppreference.com 的cond1真实分支cond1是进入循环的唯一路径,并且是始终进入循环的路径

\n
\n

应用于语句,以允许编译器针对包含该语句的执行路径比不包含此类语句的任何替代执行路径的可能性较小的情况进行优化。

\n
\n

看来是cond1受到了影响。

\n

如果我放在[[likely]]循环之后,例如do { foo(); } while(cond2); [[likely]];,则该属性将应用于空语句。该代码不直观,并且变得更不清楚是否cond2和/或cond1受到影响。

\n

顺便说一句,问题实际上是询问[[(un)likely]]属性的语义,而不是关于实现,也不是诸如__builtin_expect或打破 do-while 循环之类的替代方案foo(); while(cond2) [[unlikely]] foo();

\n

c++ c++20 likely-unlikely

11
推荐指数
1
解决办法
570
查看次数

是否有一种可移植的(C++ 标准)方法来计算先前对齐的指针?

给定[ , ] 之间的alignas(N) char buffer[N];and ,我可以使用and获得指向的指针吗?char* p&buffer[0]&buffer[N-1]buffer[0]pN

char* previous_aligned_pointer(char* ptr, size_t align) {
   // how?
}

int main() {
  constexpr int N = 32;
  alignas(N) char buffer[N];
  assert(previous_aligned_pointer(&buffer[rand() % N], N) == &buffer[0]);
}
Run Code Online (Sandbox Code Playgroud)

我想用可移植的 C++ 来完成它(如果可能的话),因此uintptr_t可能不会使用诸如将指针转换为指针然后对其执行算术之类的操作。

c++ pointers

9
推荐指数
1
解决办法
356
查看次数

未命名命名空间中的非静态未命名联合

gcc 和 msvc 无法编译这段代码,并出现错误 msg namespace-scope anonymous aggregates must be static。但是 clang 编译这个没有问题。 https://godbolt.org/z/WecT6vP91

namespace {
    union {
        int a;
        long b;
    };
}
Run Code Online (Sandbox Code Playgroud)

https://en.cppreference.com/w/cpp/language/union

命名空间范围的匿名联合必须声明为静态,除非它们出现在未命名的命名空间中

这似乎是 gcc 和 msvc 的错误?


编辑:

但是,Clang 拒绝在嵌套在未命名命名空间中的命名空间中编译非静态匿名联合。是否可以将规则更改为“...除非它们出现在直接或间接的未命名命名空间中”(这似乎还有另一个问题,见下文)或“...除非它们具有内部链接”?或者为什么不能?

namespace {
  namespace ns {
    union {
      int a;
      long b;
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

根据未命名命名空间内的名称的外部链接,未命名命名空间中的名称可以具有C语言链接。Clang 甚至接受具有 C 语言链接的非静态匿名联合,但实际上没有生成链接符号,这似乎没有意义。标准允许吗?如果允许,extern "C"内部直接或间接无名命名空间有什么影响?

namespace {
  extern "C" union {
    int a;
    long b;
  };
}
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer

9
推荐指数
1
解决办法
267
查看次数

is_copy_constructible_v&lt;const void*[N]&gt; 自 c++20 起在 GCC 上产生 true

正如标题中提到的:

#include <type_traits>

int main() {
  using Ptr = const void*;
  using Arr = Ptr[3];

  // gcc:   passed since c++20
  // clang: failed
  static_assert(std::is_copy_constructible_v<Arr>);

}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/enKre9fxr

c++20 中是否发生了导致此行为的更改?

我还发现此错误报告被标记为无效,因为

这是按照指定的方式运行的。

const void* const a[10];
const void* const b[10](a);
Run Code Online (Sandbox Code Playgroud)

是 C++20 中的有效代码;它b[0]使用&a[0]转换为 a进行初始化const void*,其余部分b使用空指针。

案例void*

void* const a[10];
void* const b[10](a);
Run Code Online (Sandbox Code Playgroud)

这是无效的,因为&a[0]是 a void* const*; void*不允许将其转换为,因为它会消除常量性。

然后我尝试了这个https://godbolt.org/z/zvTr4orvd。然而GCC无法编译b(a)b{a}没问题,但我认为这不是复制构造,而是列表初始化。我错了吗?

const void* …
Run Code Online (Sandbox Code Playgroud)

c++ type-traits c++20

8
推荐指数
0
解决办法
156
查看次数

std::less&lt;Pointer&gt; 的严格全序

这个问题来自这个评论

如果有两个向量 a 和 b,则总顺序允许为 &a[0], &b[0], &a[1], &b[1], &a[2], &b[2], ... ,即元素交错。

该命令是否被允许?

我对标准了解不多。如果我只阅读与 直接相关的部分,这似乎是正确的std::less

我发现 Herb Sutter 的 gcpp 库有类似的用法(链接):

    //  Return whether p points into this page's storage and is allocated.
    //
    inline
    bool gpage::contains(gsl::not_null<const byte*> p) const noexcept {
        //  Use std::less<> to compare (possibly unrelated) pointers portably
        auto const cmp = std::less<>{};
        auto const ext = extent();
        return !cmp(p, ext.data()) && cmp(p, ext.data() + ext.size());
    }
Run Code Online (Sandbox Code Playgroud)

c++ comparison pointers language-lawyer

7
推荐指数
1
解决办法
248
查看次数

在基类初始化的模板参数中使用 decltype 无法编译

请参阅下面的代码。为什么需要括号?它是由标准定义的吗?

现场演示: https: //godbolt.org/z/fbfPPGWc1

template<int I>
struct Base {};

template<int I>
struct Derived: Base<I>
{
  // ERROR
  Derived(int): Base<decltype(0){I}>() {}

  // OK (Note the parenthesis)
  Derived(char): Base<(decltype(0){I})>() {}

  // OK
  Base<decltype(0){I}> x = Base<decltype(0){I}>();
};

int main() {
}
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer

7
推荐指数
0
解决办法
155
查看次数

constexpr 类型化非动态未初始化存储

在 C++20 中,我们有

constexpr T* std::allocator<T>::allocate( std::size_t n );
Run Code Online (Sandbox Code Playgroud)

在编译时分配类型化动态未初始化存储(并construct_at构造对象)。

但是我们在编译时是否有类型的非动态存储,例如类型化的 aligned_storage


编辑:一种有用的用法是实现 constexpr static_vector:

template<class T, size_t Cap>
class static_vector {
    size_t size;
    Storage<T, Cap> storage;
};
Run Code Online (Sandbox Code Playgroud)

c++ c++20

6
推荐指数
1
解决办法
158
查看次数

lambda 表达式生成的函数对象的 C++ 属性?

CppCon2022 的这个演讲在 08:40 说:

在 C++23 之前,您可以为lambda 表达式生成的函数对象指定属性。

例如:

auto a = [] () [[deprecated]] { return 42; };
Run Code Online (Sandbox Code Playgroud)

然而,clang 有理由拒绝这段代码:

“已弃用”属性无法应用于类型

而 gcc 和 msvc 很乐意接受它,而不给出使用警告。

https://godbolt.org/z/Wqhq7hP6s

cppreference.com介绍 lambda 表达式的语法为(部分引用):

[捕获] (参数)规格要求(可选) { body }

  • specs - 由specifiersexceptionattrtrailing-return-type按顺序组成;这些组件中的每一个都是可选的
  • attr - 为闭包类型的函数调用运算符或运算符模板的类型 提供属性规范。如此指定的任何属性都不属于函数调用运算符或运算符模板本身,而是属于其类型。(例如,不能使用 [[noreturn]] 属性。)

那么,这是怎么回事?[[deprecated]]lambda 表达式生成的函数对象上的属性的语义是什么 ?

c++ lambda attributes language-lawyer

6
推荐指数
1
解决办法
293
查看次数