当前位置: 首页 > 知识库问答 >
问题:

使用construct_at更改活动constexpr联合成员

朱修真
2023-03-14

我正在尝试使用 construct_at 更改 constexpr 联盟的活动成员,并在构造函数使用初始值设定项列表与成员初始化其成员时出现以下错误。有人可以解释为什么吗?

#include <memory>
struct Z { 
 #if 1  // If this changes to zero it does not compile   
   constexpr Z(int x) : y(x){      
   }  
  #else  
     constexpr Z(int x) {
         y = x;      
   }  
  #endif
   int y;
};

struct W { 
   constexpr W(int x) {
      y = x;
   }   
   W(const W&) {}
   int y;
};

union U { 
   Z z;
   W w;
   constexpr U(int z) : w(z) {
   }   
};

constexpr int func() {
   constexpr U u(10);
   std::construct_at(&u.z, 10);
//   ::new (&u.z) Z(10);
   return u.z.y;
}

int main() {
    static_assert(func() == 1);
}

错误:

source>: In function 'int main()':
<source>:37:26: error: non-constant condition for static assertion
   37 |     static_assert(func() == 10);
      |                   ~~~~~~~^~~~~
<source>:37:23:   in 'constexpr' expansion of 'func()'
<source>:31:21:   in 'constexpr' expansion of 'std::construct_at<const Z, int>((& u.U::z), 10)'
/opt/compiler-explorer/gcc-11.2.0/include/c++++/11.2.0/bits/stl_construct.h:97:14:   in 'constexpr' expansion of '((Z*)<anonymous>)->Z::Z(<anonymous>)'
<source>:8:12: error: modifying a const object '((Z*)this)->Z::y' is not allowed in a constant expression
    8 |          y = x;
      |          ~~^~~
<source>:30:16: note: originally declared 'const' here
   30 |    constexpr U u(10);
      |                ^
Compiler returned: 1

共有3个答案

国晟睿
2023-03-14

我错了,这不相关。

< s >正如评论中提到的,它可以与clang的最新版本一起使用。最初在C 11中不允许在constexpr构造函数中赋值(检查7.1.5节中的$4 ),但是在C 14(同一节)中,我认为N3652允许赋值。检查(7.1.5)/3和(7.1.5)/4的相关变化。因此,如果你用GCC构建C 14,那么你会被一个编译器错误所困扰。

< s >这个答案很大程度上基于另一个SO答案。

华善
2023-03-14

正如另一个答案所指出的,u上的在这里是错误的。但是我将尝试说明您的代码的编译器行为。

std::construct_at将在给定的存储位置构造一个新对象。但是const意味着const,这意味着您正在尝试在具有自动存储持续时间的const完整对象中创建一个新对象。这是不允许的,并会导致未定义的行为。(然而,对std::construct_at的调用并非格式错误。它可以用const指针调用。)

由于这是在计算要求为常量表达式的表达式期间发生的,因此问题是这是否使表达式不是常量表达式,即编译器是否必须诊断未定义的行为。

通常,任何核心语言未定义的行为都必须由编译器诊断。编译器可以诊断任何标准库未定义的行为。

所以这里的问题是std::construct_at调用计算。函数本身被指定为等效于相应的放置新([specialized.construct]/2),除了一个特殊的例外,std::construct_at在常量表达式中是允许的,除非“底层构造函数调用取消了[表达式]作为核心常量表达式的资格”([expr.const]/6.1)。

虽然我不认为这真的很清楚,但我想这应该算作核心语言未定义行为,因为它没有违反库子句中的任何前提条件或声明的未定义行为。

这样,表达式func()==1在两个版本的代码中都不会是常量表达式,编译器应该在至少一个显示的情况下发出GCC正在执行的诊断。

然而,正如我在上面暗示的,我不相信我对常量表达式要求的解释是这里想要的。

我想 [expr.const]/6.1 也可以这样解读,这样未定义的行为要求根本不适用于 std::construct_at 调用,而仅适用于底层构造函数调用。但这似乎确实是无意的。

暴夕
2023-03-14

虽然我不知道工作/不工作的构造函数的确切情况,但是您有一个< code > const expr U(10);上,稍后通过调用< code>std::construct_at(

 类似资料:
  • 我试图通过一个方法更改对象成员的值,但我不明白为什么它在这种特定情况下不起作用: 当我在全局范围内创建对象时,我不明白为什么值是3。msvc和clang在两种情况下都显示5,但不显示gcc。谁错了?

  • 我需要创建一个“滑动活动”,当用户滑动它时它会滑动。当用户向左“滑动”时,活动应该向左滑动,新的活动会从右侧来到屏幕上。你不能把它放在中间。同样的事情发生在雅虎邮件应用程序中。你可以在阅读邮件时看到这个,向左滑动邮件移动到下一封邮件。就像下面一样。 在图中,您可以看到下一封邮件(标题为“谢谢”)正在从侧面打开。在我的例子中,它们是两种不同的活动。我们还建议在当前活动的右侧显示下一个活动的一小部分(

  • 在C 14中,由于<code>constexpr</code>不再是隐式<code>常量</code<,所以<code>constexpr<-code>成员函数是否可以修改类的数据成员:

  • 本文向大家介绍Android 使用Fence API获取用户活动的更改,包括了Android 使用Fence API获取用户活动的更改的使用技巧和注意事项,需要的朋友参考一下 示例 如果要检测用户何时开始或完成活动(例如步行,跑步或该DetectedActivityFence课程的其他任何活动),则可以为要检测的活动创建围栏,并在用户开始/结束时得到通知这项活动。通过使用BroadcastRece

  • 我创建了一个带有“底部导航活动”的新项目: 这是生成的代码: 如何使用底部栏更改为新片段?例如,我有3个片段:Fragment1 Fragment2和Fragment3,我想用底部栏中的3个按钮更改为它们。我还想通过左右滑动手指来切换片段,我该怎么做?

  • 问题内容: 我想将自己更改为我尝试过的内容,但无法将我的活动更改为片段。有人可以告诉我该怎么做吗?在哪里编辑我是Android上的新手。请告诉我和在此先感谢 这是我的活动: 问题答案: 只要了解一些步骤,您就可以现在和将来轻松地将Activity转换为Fragment ..: 首先,不要扩展,只要扩展.. 例如: 然后覆盖.. 然后通过LayoutInflater扩展布局,并分配给进一步用于子视图