小编Cas*_*eri的帖子

Do std::min(0.0, 1.0) and std::max(0.0, 1.0) yield undefined behavior?

The question is pretty clear. The following gives the reason why I think these expressions might yield undefined behavior. I would like to know whether my reasoning is right or wrong and why.

Short read:

(IEEE 754) double is not Cpp17LessThanComparable since < is not a strict weak ordering relation due to NaN. Therefore, the Requires elements of std::min<double> and std::max<double> are violated.

Long read:

All references follow n4800. Specifications of std::min and std::max are given …

c++ floating-point undefined-behavior c++-standard-library language-lawyer

50
推荐指数
2
解决办法
1287
查看次数

C++编译器在封装行为上有所不同 - 哪一个正确?

编译器(clang-5.0.0,GCC-7.3,ICC-18MSVC-19)发散的成员的可访问性WRT A下面.

class A {

    template <class> static constexpr int f() { return 0; }

    template <int> struct B {};

    template <class T> using C = B<f<T>()>;

};
Run Code Online (Sandbox Code Playgroud)

确实,请考虑以下用法:

template <class T> using D = A::C<T>;

int main() {
                        //    | clang | gcc | icc | msvc
    (void) A::f<int>(); // 1: | f     | f   | f   | f, (C)
    (void) A::B<0>{};   // 2: | B     |     | B   | …
Run Code Online (Sandbox Code Playgroud)

c++ gcc encapsulation private clang

38
推荐指数
1
解决办法
568
查看次数

关于ADC -1(0xFFFFFFFF)有什么特别之处吗?

在我的一个研究项目中,我正在编写C ++代码。但是,生成的程序集是项目的关键点之一。C ++不提供对标志操作指令的直接访问,特别是对C ++,ADC但只要编译器足够聪明地使用它,这就不成问题。考虑:

constexpr unsigned X = 0;

unsigned f1(unsigned a, unsigned b) {
    b += a;
    unsigned c = b < a;
    return c + b + X;
}
Run Code Online (Sandbox Code Playgroud)

Variable c是一种变通方法,可让我掌握进位标志并将其添加到b和中X。看起来我很幸运,(g++ -O3,版本9.1)生成的代码是这样的:

f1(unsigned int, unsigned int):
 add %edi,%esi
 mov %esi,%eax
 adc $0x0,%eax
 retq 
Run Code Online (Sandbox Code Playgroud)

对于X我测试过的所有值,代码均与上面相同(当然,立即$0x0更改的立即值除外)。但我发现了一个例外:何时X == -1(或0xFFFFFFFFu~0u,...的拼写方式并不重要)生成的代码为:

f1(unsigned int, unsigned int):
 xor %eax,%eax
 add %edi,%esi
 setb %al
 lea -0x1(%rsi,%rax,1),%eax
 retq …
Run Code Online (Sandbox Code Playgroud)

c++ x86 assembly gcc bigint

38
推荐指数
1
解决办法
1672
查看次数

CRTP和多级继承

我的一个朋友问我"如何使用CRTP替换多级继承中的多态".更准确地说,在这种情况下:

struct A {

  void bar() {
    // do something and then call foo (possibly) in the derived class:
    foo();
  }

  // possibly non pure virtual
  virtual void foo() const = 0;
}

struct B : A {
  void foo() const override { /* do something */ }
}

struct C : B {
  // possibly absent to not override B::foo().
  void foo() const final { /* do something else */ }
}
Run Code Online (Sandbox Code Playgroud)

我和我的朋友都知道CRTP不是多态的替代品,但我们对可以使用这两种模式的情况感兴趣.(为了这个问题,我们对每种模式的利弊都不感兴趣.)

  1. 之前已经问过这个问题,但事实证明作者想要实现命名参数idiom …

c++ inheritance crtp static-polymorphism c++11

23
推荐指数
3
解决办法
5347
查看次数

使用表达式模板时,根据lvalue/rvalue提供类的不同实现

问题

假设我们实现了一个string表示字符串的类.然后我们想要添加一个operator+连接两个strings的,并决定通过表达式模板实现它,以避免在执行时进行多次分配str1 + str2 + ... + strN.

运算符将如下所示:

stringbuilder<string, string> operator+(const string &a, const string &b)
Run Code Online (Sandbox Code Playgroud)

stringbuilder是一个模板类,它反过来重载operator+并具有隐式string转换运算符.几乎是标准的教科书练习:

template<class T, class U> class stringbuilder;

template<> class stringbuilder<string, string> {
    stringbuilder(const string &a, const string &b) : a(a), b(b) {};
    const string &a;
    const string &b;
    operator string() const;
    // ...
}

// recursive case similar,
// building a stringbuilder<stringbuilder<...>, string>
Run Code Online (Sandbox Code Playgroud)

只要有人这样做,上述实现就完美无缺

string result = str1 …
Run Code Online (Sandbox Code Playgroud)

c++ expression-templates auto c++11

20
推荐指数
1
解决办法
734
查看次数

"const T*"可以匹配指向自由函数的指针吗?

在一个相关的问题中,它说没有指向非成员const函数的指针.另外,C++ 11 8.3.5/6说

cv-qualifier-seq在函数声明符中的作用与在函数类型之上添加cv-qualification不同.在后一种情况下,忽略cv限定符.[注意:具有cv-qualifier-seq的函数类型不是cv限定类型; 没有cv限定的函数类型. - 尾注]

如果我理解正确,这意味着没有非成员const函数.(虽然这些函数不是常量,但不能按照3.10/6进行修改).特别是,指向const函数的指针是没有意义的.

但是,似乎有些编译器会在类型推导上下文中创建指向const函数的指针.例如,考虑代码:

#include <iostream>

void f() {}

template <typename T> void g(      T*) { std::cout << "non const" << std::endl; }
template <typename T> void g(const T*) { std::cout << "const    " << std::endl; }

int main() {
     g(f);
}
Run Code Online (Sandbox Code Playgroud)

当使用GCC和Intel编译时,代码输出"非常量",正如我从上面的引用中所期望的那样.但是,使用Clang和Visual Studio编译时输出为"const".

我的解释是否正确?

更新:

在评论之后,我试图澄清我不是在讨论const成员函数.我对非成员函数感兴趣(但同样的参数也可能适用于非静态成员函数).我也改变了问题标题,使其更精确.

g(f)上面提到的解决方案一致,以下行对于GCC和英特尔而言是非法的,但对于Clang和Visual Studio则不行

const auto* ptr = &f;
Run Code Online (Sandbox Code Playgroud)

更新2:

我同意Andy Prowl的解释,并选择了他的答案.然而,在那之后,我意识到这个问题是CWG 公开问题.

c++ const function-pointers c++11

18
推荐指数
1
解决办法
791
查看次数

类可以坚不可摧(没有析构函数)吗?

考虑:

#include <type_traits>

template <typename T>
struct A {
  ~A() requires(std::is_void_v<T>);
  //~A() requires(!std::is_void_v<T>) = default;
};

template struct A<int>;
Run Code Online (Sandbox Code Playgroud)

我认为一个类不可能没有析构函数,gcc 13.2 似乎同意我的观点,但 clang 17.0 和 msvc 19.38 不同意并抱怨:

[clang] error: no viable destructor found for class 'A<int>'
[msvc ] error C7653: 'A<int>': failed to select a destructor for the class
Run Code Online (Sandbox Code Playgroud)

(将注释行添加到代码中可以解决此问题并使所有编译器满意。)

哪些编译器是正确的?标准中的相关引用是什么?

c++ language-lawyer c++20

18
推荐指数
1
解决办法
674
查看次数

编译器对析构函数省略的自由度是多少?

众所周知,在某些条件下,编译器可能会忽略对复制构造函数的调用.但是,标准清楚地表明编译器只能自由地更改运行时行为(调用或不调用复制构造函数),但执行转换就像调用复制构造函数一样.特别是,编译器检查是否有一个有效的复制构造函数来调用.

我遇到了一个情况,可能会省略析构函数调用,但编译器在是否需要存在有效的析构函数方面存在差异.

这是一个完整的示例,说明了此问题可能如何发生以及编译器的行为方式有何不同.

template <typename T>
struct A {
  ~A() { (void) sizeof(T); }
};

struct B;    // defined elsewhere.

struct C {
  A<B> x, y;
  ~C();      // defined in a TU where B is complete.
};

int main() {
  C c;
}
Run Code Online (Sandbox Code Playgroud)

编译时main()编译生成C的默认构造函数.此构造函数默认首先初始化x然后再初始化y.如果在y施工期间抛出异常,则x必须销毁.生成的代码如下所示:

new ((void*) &this->x) A<B>;   // default initializes this->x.
try {
  new ((void*) &this->y) A<B>; // default initializes this->y.
}
catch (...) {
  (this->x).~A<B>();           // …
Run Code Online (Sandbox Code Playgroud)

c++ destructor language-lawyer c++11

14
推荐指数
1
解决办法
500
查看次数

右值引用可以绑定到函数吗?

我用GCC,Clang,ICC和VS测试了以下代码:

void f() {}

void g(void (&&)()) { }

int main() {
    g(f);
}
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,g采用右值引用但是f是左值,并且通常,右值引用不能绑定到左值.这正是ICC抱怨的:

error: an rvalue reference cannot be bound to an lvalue
Run Code Online (Sandbox Code Playgroud)

VS也会出错,但出于另一个原因:

error C2664: 'void h(void (__cdecl &&)(void))' : cannot convert parameter 1 from 'void (__cdecl *)(void)' to 'void (__cdecl &&)(void)'
Run Code Online (Sandbox Code Playgroud)

这告诉我VS立即执行函数到指针的转换,而不是直接绑定引用f.值得一提的是,如果我替换g(f)g(&f)那么四个编译器会产生同样的错误.

最后,GCC和Clang接受了代码,我相信它们是正确的.我的推理基于8.5.3/5

对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化为

- 如果参考是左值参考[...]

- 否则,[...] 参考应为右值参考.

     - 如果初始化表达式是 [...] 函数左值 [...]

     然后 …

c++ function rvalue-reference language-lawyer c++11

12
推荐指数
1
解决办法
595
查看次数

如何只强制类的智能指针实例?

我一直在努力防止用户使用没有智能指针的类.因此,强制它们使对象被智能指针分配和管理.为了得到这样的结果,我尝试了以下方法:

#include <memory>
class A
{
private :
    ~A {}
    // To force use of A only with std::unique_ptr
    friend std::default_delete<A>;
};
Run Code Online (Sandbox Code Playgroud)

如果您只希望您的类用户能够通过操作类的实例,那么这项工作非常好std::unique_ptr.但它不起作用std::shared_ptr.所以我想知道你是否有任何想法来获得这样的行为.我发现的唯一解决方案是执行以下操作(使用friend std::allocator_traits<A>;效率不高):

#include <memory>
class A
{
private :
    ~A {}
    // For std::shared_ptr use with g++
    friend __gnu_cxx::new_allocator<A>;
};
Run Code Online (Sandbox Code Playgroud)

但这种解决方案不可移植.也许我做错了.

c++ class-design smart-pointers c++11

12
推荐指数
1
解决办法
2578
查看次数