小编cur*_*guy的帖子

不明确的成员访问表达式:Clang拒绝有效代码吗?

我有一些代码,为了这个问题的目的,归结为

template<typename T>
class TemplateClass : public T {
 public:
  void method() {}
  template<typename U>
  static void static_method(U u) { u.TemplateClass::method(); }
};

class EmptyClass {};

int main() {
  TemplateClass<TemplateClass<EmptyClass> > c;
  TemplateClass<EmptyClass>::static_method(c);
}
Run Code Online (Sandbox Code Playgroud)

我试图用两个版本的两个编译器来编译它.GCC 4.2,4.4,4.6接受它而没有投诉.截至11月14日的Clang 2.9和SVN中继拒绝它,并显示以下错误消息:

example.cc:6:38: error: lookup of 'TemplateClass' in member access expression is
      ambiguous
  static void static_method(U u) { u.TemplateClass::method(); }
                                     ^
example.cc:13:3: note: in instantiation of function template specialization
      'TemplateClass<EmptyClass>::static_method<TemplateClass<TemplateClass<EmptyClass>
      > >' requested here
  TemplateClass<EmptyClass>::static_method(c);
  ^
example.cc:2:7: note: lookup in the object type
      'TemplateClass<TemplateClass<EmptyClass> >' …
Run Code Online (Sandbox Code Playgroud)

c++ gcc clang language-lawyer name-lookup

23
推荐指数
2
解决办法
1855
查看次数

为什么这个调用swap()模棱两可?

以下程序

#include <algorithm>
#include <utility>
#include <memory>

namespace my_namespace
{


template<class T>
void swap(T& a, T& b)
{
  T tmp = std::move(a);
  a = std::move(b);
  b = std::move(tmp);
}

template<class T, class Alloc = std::allocator<T>>
class foo {};

}

int main()
{
  my_namespace::foo<int> *a, *b;

  using my_namespace::swap;

  swap(a,b);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

导致两者g++clang在我的系统上发出以下编译器错误:

$ clang -std=c++11 swap_repro.cpp -I.
swap_repro.cpp:28:3: error: call to 'swap' is ambiguous
  swap(a,b);
  ^~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/bits/algorithmfwd.h:571:5: note: candidate function [with _Tp = my_namespace::foo<int, std::allocator<int> > …
Run Code Online (Sandbox Code Playgroud)

c++ namespaces class-template name-lookup argument-dependent-lookup

23
推荐指数
2
解决办法
1643
查看次数

标准对未对齐的内存访问有何看法?

我搜索了关于未对齐访问的标准,但没有找到任何东西(也许我是无意的).

是不确定的行为?它是实现定义的吗?

由于许多当前的CPU支持未对齐访问,因此未对齐的内存访问是实现定义的,这是明智的.是这样的吗?

通过未对齐访问,我的意思是例如:

alignas(int) char buffer[sizeof(int)+1];
int &x = *new(buffer+1) int;
x = 42;
Run Code Online (Sandbox Code Playgroud)

c++ memory-alignment language-lawyer c++17

23
推荐指数
1
解决办法
1334
查看次数

如何在C++中正确访问映射内存而没有未定义的行为

我一直试图弄清楚如何从C++ 17访问映射缓冲区而不调用未定义的行为.对于这个例子,我将使用Vulkan的返回缓冲区vkMapMemory.

因此,根据N4659(最终的C++ 17工作草案),[intro.object]部分(重点补充):

C++程序中的构造创建,销毁,引用,访问和操作对象.一个目的是通过一种创建定义(6.1),通过一个 新的表达式 (8.3.4)中,当隐式地改变所述一个联合的活性部件(12.3),或当一个临时对象被创建(7.4,15.2).

显然,这些是创建C++对象的唯一有效方法.因此,假设我们得到一个void*指向主机可见(和相干)设备内存的映射区域的指针(当然,假设所有必需的参数都有有效值并且调用成功,并且返回的内存块足够大)正确对齐):

void* ptr{};
vkMapMemory(device, memory, offset, size, flags, &ptr);
assert(ptr != nullptr);
Run Code Online (Sandbox Code Playgroud)

现在,我希望将此内存作为float数组访问.显而易见的事情static_cast是指针并按照我的快乐方式继续如下:

volatile float* float_array = static_cast<volatile float*>(ptr);
Run Code Online (Sandbox Code Playgroud)

(volatile包含它因为它被映射为相干存储器,因此可以在任何时候由GPU写入).然而,在该存储器位置中技术上float不存在阵列,至少不是在引用的摘录的意义上,因此通过这样的指针访问存储器将是未定义的行为.因此,根据我的理解,我有两种选择:

1. memcpy数据

它应该总是能够使用本地缓存,将它转换为std::byte*memcpy表示到映射区域.GPU将按照着色器中的指示解释它(在这种情况下,作为32位数组float),从而解决了问题.但是,这需要额外的内存和额外的副本,所以我宁愿避免这种情况.

2.放置 - new阵列

看来,[new.delete.placement]部分没有对如何获得放置地址施加任何限制(无论实现的指针安全性如何,它都不必是安全派生的指针).因此,可以通过放置创建有效的浮点数组new,如下所示:

volatile …
Run Code Online (Sandbox Code Playgroud)

c++ volatile language-lawyer mapped-memory c++17

23
推荐指数
1
解决办法
906
查看次数

为什么虚拟分配的行为与同一签名的其他虚拟功能不同?

在玩实现虚拟赋值运算符的过程中,我以一种有趣的行为结束了.它不是编译器故障,因为g ++ 4.1,4.3和VS 2005共享相同的行为.

基本上,虚拟运算符=与实际执行的代码相比,其行为与任何其他虚拟函数不同.

struct Base {
   virtual Base& f( Base const & ) {
      std::cout << "Base::f(Base const &)" << std::endl;
      return *this;
   }
   virtual Base& operator=( Base const & ) {
      std::cout << "Base::operator=(Base const &)" << std::endl;
      return *this;
   }
};
struct Derived : public Base {
   virtual Base& f( Base const & ) {
      std::cout << "Derived::f(Base const &)" << std::endl;
      return *this;
   }
   virtual Base& operator=( Base const & ) {
      std::cout << "Derived::operator=( …
Run Code Online (Sandbox Code Playgroud)

c++ inheritance virtual-functions assignment-operator

22
推荐指数
2
解决办法
3483
查看次数

浮点和严格别名

我试图从浮点数中提取位而不调用未定义的行为.这是我的第一次尝试:

unsigned foo(float x)
{
    unsigned* u = (unsigned*)&x;
    return *u;
}
Run Code Online (Sandbox Code Playgroud)

据我了解,由于严格的别名规则,这不能保证工作,对吧?如果使用字符指针进行中间步骤,它是否有效?

unsigned bar(float x)
{
    char* c = (char*)&x;
    unsigned* u = (unsigned*)c;
    return *u;
}
Run Code Online (Sandbox Code Playgroud)

或者我是否必须自己提取单个字节?

unsigned baz(float x)
{
    unsigned char* c = (unsigned char*)&x;
    return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
Run Code Online (Sandbox Code Playgroud)

当然,这有一个缺点,取决于字节顺序,但我可以忍受.

工会黑客肯定是未定义的行为,对吧?

unsigned uni(float x)
{
    union { float f; unsigned u; };
    f = x;
    return u;
}
Run Code Online (Sandbox Code Playgroud)

为了完整起见,这里有一个参考版本foo.也是未定义的行为,对吗?

unsigned ref(float x)
{ …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point bits strict-aliasing type-punning

22
推荐指数
3
解决办法
2460
查看次数

为什么不允许在constexpr函数中转到?

C++ 14规定了constexpr函数中可以做什么和不可以做什么.其中一些(不asm,没有静态变量)似乎很合理.但该标准也不允许gotoconstexpr功能,尽管它允许其他控制流机制.
这种区别背后的原因是什么?
我以为我们过去了" goto很难编译 ".

c++ goto language-lawyer constexpr c++14

22
推荐指数
1
解决办法
892
查看次数

为什么 C 中的绝对值函数不接受常量输入?

在 C 中,绝对值函数(接受浮点数)的原型是

 float fabsf( float );
Run Code Online (Sandbox Code Playgroud)

为什么这个原型不接受一个常量值,像这样:

 float fabsf( float const );
Run Code Online (Sandbox Code Playgroud)

fabsf 不会改变输入的值,是吗?

如果我有一个接受输入并调用 fabsf 的函数,我是否被迫避免将输入指定为 const?

在这种情况下处理常量正确性的适当方法是什么?

c constants function pass-by-value

22
推荐指数
4
解决办法
2775
查看次数

构造函数的初始化列表中的'this'指针

我想我无法理解为什么这不起作用.我一直以为我可以在构造函数中使用'this'指针,但我从来不知道我不能在初始化列表中使用'this'.

#include <iostream>

class A {
    public:
        int a;
        int b;
        A(int a = 0, int b = 0) : this->a(a), this->b(b) { }
        void print() {
        std::cout << a << ", " << b << std::endl;
    }
};

int main() {
    A a;
    a.print();
}
Run Code Online (Sandbox Code Playgroud)

我很想知道与之相关的细节.

c++ this syntax-error language-lawyer ctor-initializer

21
推荐指数
2
解决办法
2191
查看次数

显式调用析构函数

我偶然发现了以下代码片段:

#include <iostream>
#include <string>
using namespace std;
class First
{
    string *s;
    public:
    First() { s = new string("Text");}
    ~First() { delete s;}
    void Print(){ cout<<*s;}
};

int main()
{
    First FirstObject;
    FirstObject.Print();
    FirstObject.~First();
}
Run Code Online (Sandbox Code Playgroud)

该文本表示此代码段应该导致运行时错误.现在,我对此并不十分肯定,所以我尝试编译并运行它.有效.奇怪的是,尽管所涉及的数据非常简单,但在打印"文本"之后程序结结巴巴,并且仅在一秒钟之后完成.

我添加了一个要打印到析构函数的字符串,因为我不确定显式调用这样的析构函数是否合法.程序打印两次字符串.所以我的猜测是析构函数被调用两次,因为正常的程序终止不知道显式调用并试图再次销毁对象.

一个简单的搜索确认显式调用自动化对象上的析构函数是危险的,因为第二次调用(当对象超出范围时)具有未定义的行为.所以我很幸运,我的编译器(VS 2017)或这个特定的程序.

关于运行时错误,文本是否完全错误?或者运行时错误真的很常见吗?或者也许我的编译器实现了某种针对这类事情的warding机制?

c++ destructor lifetime undefined-behavior explicit-destructor-call

21
推荐指数
3
解决办法
2223
查看次数