小编Jan*_*tke的帖子

为 GCC 复制 clang 的 __builtin_assume

最近,我发现void __builtin_assume(bool)了 clang,它可以向编译器提供有关程序状态的附加信息。这可以产生巨大的差异,例如

#include <cstddef>

// compiles to about 80 instructions at -O3
unsigned sum(unsigned data[], size_t count) {
    unsigned sum = 0;
    for (size_t i = 0; i < count; ++i) {
        sum += data[i];
    }
    return sum;
}

// compiles to about 10 instructions at -O3
unsigned sum_small(unsigned data[], size_t count) {
    __builtin_assume(count <= 4);
    unsigned sum = 0;
    for (size_t i = 0; i < count; ++i) {
        sum += data[i];
    }
    return …
Run Code Online (Sandbox Code Playgroud)

c++ gcc clang built-in assumption

6
推荐指数
2
解决办法
3571
查看次数

使用 std::function 和模板参数将函数传递给函数

我试图将一个指向谓词函数的指针传递给FooBar函数。该Bar函数工作正常,但该Foo函数引发编译时错误:

错误:没有匹配的调用函数 Foo<int>(bool (&)(int))

为什么编译器会引发错误?' 解包后' Foos 和Bar's 模板参数类型之间有什么区别Args吗?

#include <functional>

bool predicate(int a) {
    return (a > 5);
}

// sizeof...(Args) == 1 and I suppose it is int
template<typename... Args>
void Foo(std::function<bool(Args...)> predicate) {
    // clang: note: candidate template ignored:
    //        could not match 'function<bool (int, type-parameter-0-0...)>' 
    //        against 'bool (*)(int)'
}

template<typename Args>
void Bar(std::function<bool(Args)> predicate) {

}

int main(int argc, char const *argv[]) …
Run Code Online (Sandbox Code Playgroud)

c++ templates type-inference variadic-templates std-function

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

带维数的多维数组模板

我想制作一个NDArray具有固定尺寸的模板,但可以在每个尺寸上调整大小。

我的问题是如何让它能够根据使用了多少对来推断构造函数中的尺寸{}?构造函数中的元素将用于初始化一些元素。

#include <array>
#include <iostream>

template<typename T, size_t Dimension>
class NDArray
{
    T* buffer = nullptr; //flattened buffer for cache locality
    std::array<size_t, Dimension> dimension;    //keep the current sizes of each dimension
public:
    NDArray(std::initializer_list<T> elements) : dimension{elements.size()}   //for 1D
    {
        std::cout << "Dimension = " << Dimension << '\n';
    }
    NDArray(std::initializer_list<NDArray<T, Dimension-1>> list) //how to make this works???
    {
        std::cout << "Dimension = " << Dimension << '\n';
    }
};

template<typename T, size_t N>
NDArray(const T(&)[N]) …
Run Code Online (Sandbox Code Playgroud)

c++ templates multidimensional-array c++17 deduction-guide

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

整数提升带来的 std::byte 开销

考虑unsigned char v进行一系列按位运算并将结果存储回 的情况v。在底层,它被整数提升一次,经历一系列操作,结果被截断并存储回v

然而std::byte v,对于每个操作,操作数首先被提升为整数,进行操作,并且(中间)结果被截断并存储回某个std::byte。这将是许多来回的提升和截断。这都是概念性的,但它会在实践中造成真正的开销吗?

人工例子

// `mask` and `lshf` are of type `unsigned`
unsigned char v = ...;
v = (v & mask) << lshf; // one promotion at `&` and one truncation at `=`
Run Code Online (Sandbox Code Playgroud)
// `mask` and `lshf` are of type `std::byte` and `unsigned`
std::byte v = ...;
v = (v & mask) << lshf;

// It would be like
// byte(unsigned(byte(unsigned(v) & unsigned(mask))) << …
Run Code Online (Sandbox Code Playgroud)

c++ type-conversion integer-promotion c++17 std-byte

6
推荐指数
0
解决办法
122
查看次数

可变数据成员、模板构造函数和普通复制构造函数

示例代码可以在下面或godbolt上找到。假设我们有 4 个班级:

  1. S<T>:持有数据成员。

  2. SCtor<T>:持有数据成员并具有模板构造函数。

  3. SCtorMutable<T>:持有可变数据成员并具有模板构造函数。

  4. SCtorDefault<T>:持有一个成员,有一个模板构造函数,有默认的复制/移动构造函数和默认的复制/移动赋值运算符。

所有编译器都同意这 4 个类是可以简单复制的。

如果有一个简单的包装类W<T>将上述任何一个类作为数据成员。包装类W<S...<T>>仍然是可简单复制的。

如果有另一个包装类WMutable<T>将上述类中的任何一个保存为可变数据成员。

  1. MSVC 仍然认为WMutable<S...<T>>是可以简单复制的。
  2. clang 认为WMutable<S<T>>是可以复制的。WMutable<SCtor...<T>>不是可简单复制构造的,因此也不是可简单复制的。
  3. gcc 认为WMutable<S<T>>是可以简单复制的。WMutable<SCtor...<T>>不是可简单复制构造的,而是可简单复制的。

应该WMutable<T>是可以简单复制的吗?

#include <type_traits>
#include <utility>

template<typename T>
struct S {
    T m_t;
};

template<typename T>
struct SCtor {
    T m_t;
    template<typename... U>
    SCtor(U&&... u): m_t(std::forward<U>(u)...) {}
};

template<typename T>
struct SCtorMutable {
    mutable T m_t;
    template<typename... U> …
Run Code Online (Sandbox Code Playgroud)

c++ mutable copy-constructor language-lawyer trivially-copyable

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

为什么 Rust 字符串没有短字符串优化 (SSO)?

我查看了 的源代码String,发现它是根据 实现的Vec,它没有任何形式的小对象优化:

pub struct String {
    vec: Vec<u8>,
}
Run Code Online (Sandbox Code Playgroud)

来自 C++,其中每个主要标准库都使用短字符串优化 (SSO) std::string,这是非常令人惊讶的。字符串的许多用例都涉及非常短的字符串,例如:

  1. 如果您正在编写编译器,您将拥有关键字和标记的字符串,例如"==", "pub","delete"
  2. 如果您要对枚举进行字符串化,则所有常量名称通常都足够短以适合 SSO 缓冲区
  3. 如果您使用格式字符串打印内容,则格式字符串很少会太长以至于不适合 SSO
  4. 如果您使用键和值解析配置文件,则键和值通常都很短,例如setting: enabled
  5. 如果您要存储正则表达式,它们通常也适合 SSO
  6. 如果您要存储字典,则几乎可以对整个字典进行 SSO,因为例如英语单词相当短

鉴于此,默认情况下不使用任何 SSO 的理由是什么String?是否可以追溯添加该功能?是否有任何分析数据可以证明 SSO 是否有帮助?

C++ 中 SSO 的注释

SSO 是通过重用容器的内存来完成的std::string,否则容器将存储指针、大小和容量来存储:

  • 内部字符串的大小(可以只是一个字节)
  • 容器中的字符串数据(通常最大长度约为 20 字节)

也有可能只重用容量,并且有一个指向字符串对象内部的指针。所有这些通常都是通过 , 完成的union,并且在 Rust 中也是可能的。

string rust

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

为什么[[假设]]不被评估但也可能被评估?

cppreference页面[[assume]]说:

[[assume( expression )]] 
Run Code Online (Sandbox Code Playgroud)

[...] 表达式没有被求值(但它仍然可能被求值)。

这个措辞让我很困惑。这里 cppreference 错了吗?如果不评估,为什么可能会评估?它不是像 中的表达式一样未计算的操作数吗sizeof?如果不可以,后果是什么?

c++ attributes language-lawyer c++23 assumption

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

全局变量和静态内联数据成员相对于彼此的初始化顺序是否得到保证?

下面的代码在同一个翻译单元中,并且A::v在之后定义的x,为什么A::v没有初始化为“ok”?

#include <string>
#include <iostream>

std::string foo() {
    return "OK";
}

std::string x = foo();


struct A {
    static inline std::string v = x;
};

int main() {
    std::cout << A::v << std::endl; // didn't print "OK", why?
}

Run Code Online (Sandbox Code Playgroud)

c++ static-members initialization-order language-lawyer c++17

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

仅当提供了模板参数时,如何才能启用类模板成员函数?

是否可以有一个带有可选模板参数的类,可以像这样调用?:

#include <iostream>

template <typename T = void>
class A final
{
public:
    // This class can be called only when T exists.
    void f()
    {
        printf("%d\n", member);
    }

    // This method can be called only when T is missing.
    void g()
    {
        printf("No template parameter\n");
    }
public:
    T member;
};

int main()
{

    A<int> a1;
    A a2;
    a1.f(); // should be valid
    a1.g(); // should be invalid, cannot compile
    a2.f(); // should be invalid, cannot compile
    a2.g(); // should …
Run Code Online (Sandbox Code Playgroud)

c++ templates member-functions c++-concepts c++20

6
推荐指数
2
解决办法
194
查看次数

using 命名空间指令是否使名称在内联函数中可用?

考虑声明一个不受约束的ns::operator*. using namespace ns在块作用域中并调用函数之后foo<T>,clangns::operator*在读取内部基于范围的循环的迭代器时使用foo。没有其他类型ns涉及其他类型,因此 ADL 应该不会产生任何候选者。

在以下示例中,static_assert失败并显示消息:

错误:由于要求 'std::is_same_v<const int &, const custom_type &>',静态断言失败

汇编代码显示这ns::operator*是由 clang 使用的。gcc 和 msvc 的断言都通过了!

namespace ns {

template <typename T>
constexpr auto operator*(T&& /*value*/) {
    struct custom_type {};
    return custom_type{};
};

}  // namespace ns

template <typename T>
constexpr void foo() {
    std::vector<T> vec{};
    for (const auto& curr : vec) {
        static_assert(std::is_same_v<const T&, decltype(curr)>);
    }
}

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

c++ templates namespaces using compiler-bug

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