我想实现从shared_ptr扩展的自己的指针(使用少量辅助方法)。
class Event;
class EventPtr : public std::shared_ptr<Event> {
public:
constexpr EventPtr()
: std::shared_ptr<Event>() {
}
constexpr EventPtr(std::nullptr_t p)
: std::shared_ptr<Event>(p) {
}
explicit EventPtr(Event* ptr)
: std::shared_ptr<Event>(ptr) {
}
};
问题是编译器为两个constexpr构造函数给出了以下错误: constexpr构造函数从不生成常量表达式
请告诉我如何修复它。
答案 0 :(得分:4)
constexpr构造函数的规则在C ++ 11和C ++ 14之间发生了变化;请参阅DR1911 constexpr constructor with non-literal base class和this bug。
修复是以C ++ 14模式(-std=c++14
)编译。
C ++ 11中的语言 [dcl.constexpr] :
对于constexpr函数,如果不存在函数参数值,使得函数调用替换将产生常量表达式(5.19),则程序格式错误;无需诊断。对于constexpr构造函数,如果不存在参数值,那么在函数调用替换之后,每个都是 mem-initializers中的构造函数调用和完全表达式将是一个常量表达式(包括转换),程序格式不正确;无需诊断。
在C ++ 11下,shared_ptr
可以有constexpr
个构造函数,但是继承自shared_ptr
或shared_ptr
成员的任何类类型都不能,因为shared_ptr
不是文字类型(它有一个析构函数),因此不能出现在常量表达式中。对于C ++ 14,这简化为:
对于非模板,非默认constexpr函数或非模板,非默认,非继承constexpr构造函数,如果不存在参数值,则函数或构造函数的调用可以是已计算的子表达式一个核心常数表达式(5.19),该程序是不正确的;无需诊断。
不幸的是,这使得非文字类型的所有 constexpr构造函数都是未定义的行为; DR1911通过添加子条款(粗体)来修复此问题:
对于非模板,非默认constexpr函数或非模板,非默认,非继承constexpr构造函数,如果不存在参数值,则函数或构造函数的调用可以是已计算的子表达式核心常量表达式(5.20),或者,对于构造函数,某个对象的常量初始化程序(3.6.2),程序格式不正确;无需诊断。
struct X { ~X() {} constexpr X() {} }; // OK in C++11, UB in C++14, OK since DR1911
struct Y : X { constexpr Y() : X() {} }; // UB in C++11, UB in C++14, OK since DR1911