以下声明在clang 3.8.1中失败,但似乎在其他测试的编译器中编译时没有错误(例如gcc 6.1,MSVC 2015,clang 3.9.1)。
constexpr std::integral_constant<int,0> myConstant;
clang 3.8.1给出:
error: default initialization of an object of const type 'const std::integral_constant<int, 0>' without a user-provided default constructor constexpr std::integral_constant<int,0> myConstant;
以下在所有测试的编译器中正确编译:
constexpr std::integral_constant<int,0> myConstant = {};
这里发生了什么? (铿锵声3.8.1错误是否正确?)
如果我定义自己的类型,是否应该编写用户提供的默认ctor,以便用户可以避免键入={}
?
答案 0 :(得分:1)
constexpr
变量必须初始化。 Typename variablename;
形式的声明将在variablename
上执行默认初始化。
在默认初始化下,没有普通默认构造函数的类型将是未初始化。通常没关系。
但constexpr
变量不允许未初始化。因此,对于具有普通默认构造函数的类型,您必须可视地初始化它们。通过对变量执行= {}
,您将使其初始化值,这将使对象清零。
这不应被视为问题。通常,您应该始终明显初始化constexpr
变量,即使它只是= {}
。这样,每个人都清楚你在做什么。
不,你不应该只为类型添加默认构造函数,以便人们可以在不明显初始化它们的情况下制作它们的constexpr
个变量。如果类型需要一个来完成其工作,则只应将用户提供的默认构造函数添加到类型中。
至于编译器的行为,那就是它们。 Clang在3.8.1中的行为在规范方面是正确的,因此其他行为是不正确的。
答案 1 :(得分:0)
根据这个答案:https://stackoverflow.com/a/28338265/2013747,是否需要={}
是一个公开的问题,clang和gcc最初选择以不同方式实施。允许={}
被忽略似乎是CWG首选的方向,而clang 3.9改变了政策以反映这一点。
引用CWG活动问题#253:
253。为什么必须初始化空对象或完全初始化的const对象?
[]
8.6 [dcl.init]第9段说:
如果没有为对象指定初始化程序,并且该对象属于(可能是> cv限定的)非POD类类型(或其数组),则该对象应为&gt;默认初始化;如果对象是const限定类型,则基础&gt;类类型应具有用户声明的默认构造函数。否则,如果没有为对象指定&gt;初始化程序,则该对象及其子对象(如果有)&gt;具有不确定的初始值;如果对象或其任何子对象都是const限定类型,则该程序格式不正确。
如果const POD对象没有非静态数据成员怎么办? 此措辞要求此类案例的空初始值设定项 [...]
(强调补充。)这里的结论是,为了与较旧的编译器兼容,并严格遵守标准,必须使用={}
,除非有用户声明的默认ctor。
旧的铿锵行为是由于上述保守的解释所致 语言规范。 CWG 2011年8月会议决定:
2011年8月会议记录:
如果隐式默认构造函数初始化所有子对象,则不需要初始化程序。
来源:http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253
据我所知,此更改尚未纳入任何版本的C ++标准。因此,虽然省略={}
可能会继续编译,并且可能在将来得到该标准的正式支持,但它目前不是官方ISO标准的一部分。