C++ 可以添加';constexpr';改变行为?

C++ 可以添加';constexpr';改变行为?,c++,c++11,constexpr,C++,C++11,Constexpr,给定两个程序,其中源代码的唯一区别在于是否存在一个constexpr,该程序的含义是否可能发生变化 换句话说,如果有一个编译器选项,要求编译器尽可能努力推断constexpr,它会破坏现有的标准代码和/或以不好的方式改变其含义吗 想象一下,在处理一个代码库时,原始开发人员忘记在可能的地方包括constexpr,可能是在C++11之前编写的代码。如果编译器能够推断出constexpr来帮助您继续工作,那就太好了。当然,它可能还应该在每次执行此推断时发出警告,鼓励您稍后显式添加constepr。但它

给定两个程序,其中源代码的唯一区别在于是否存在一个
constexpr
,该程序的含义是否可能发生变化

换句话说,如果有一个编译器选项,要求编译器尽可能努力推断
constexpr
,它会破坏现有的标准代码和/或以不好的方式改变其含义吗

想象一下,在处理一个代码库时,原始开发人员忘记在可能的地方包括
constexpr
,可能是在C++11之前编写的代码。如果编译器能够推断出
constexpr
来帮助您继续工作,那就太好了。当然,它可能还应该在每次执行此推断时发出警告,鼓励您稍后显式添加
constepr
。但它仍然是有用的。我担心它会把东西弄坏

到目前为止,我唯一能想到的是
constexpr
函数是隐式
inline
的,在某些情况下,添加
inline
可能会以不好的方式改变事情;例如,如果您违反了“一个定义”规则

给定两个程序,其中源代码的唯一区别是 一个constexpr的存在或不存在,是否可能 节目有什么变化

是的,这至少适用于constexpr函数。这就是为什么不允许实现选择标记为constexpr的标准函数的原因,主要问题是用户可能通过SFINAE观察到不同的行为。这是记录在案的,其中说(我的重点):

在提交全体委员会表决时表示了一些关切 向WP说明,该问题已在没有充分证据的情况下得到解决 考虑到不同库实现的后果, 因为用户可以使用SFINAE观察与其他相同代码不同的行为。问题已移回审阅状态,并将被删除 在波特兰与更大的团队再次讨论。波特兰的注释: John Spicer已同意在任何此类会议上代表Core的关注点 LWG内部的讨论


有一个简单的窍门:

template<int n>struct i{};
int foo(int){return 0;}
constexpr int foo(char){return 'a';}

template<class T=int, T x=1,i<foo(x)>* =nullptr>
bool bar(){return true;}
template<class T=int, T x=1,class...Ts>
bool bar(Ts...){return false;}
templatestruct i{};
int foo(int){返回0;}
constexpr int foo(char){返回'a';}
模板
boolbar(){return true;}
模板
布尔条(Ts..{返回false;}
如果
intfoo(int)
是constexpr,默认情况下会选择另一个
条的重载

运行不同的代码时,可能会发生任何行为更改

(只需更改注释掉的
#define X


示例的设计:

char
重载可防止上述代码格式错误,无需诊断,因为所有模板都必须具有有效的专门化<代码>foo
提供了该功能。在实践中,它的存在不是必需的:ADL可以从很远的地方找到一个
foo
,在
某个类型*
上重载,然后将
某个类型*
作为
T
传递。这意味着没有编译单位可以证明代码格式错误


Ts..
使
bar
过载不太受欢迎。因此,如果第一个匹配,就没有歧义。只有当第一个重载无法匹配时(由于
foo(x)
不是
constexpr
)才会调用第二个重载(或者,如果有人向其传递参数)。

,例如,如果编译器供应商选择将标准中未标记的函数标记为constexpr,这可能会通过SFINAE导致不同的行为,这就是为什么最终不允许这样做的原因,请参见@ShafikYaghmour感谢。我曾用SFINAE做过一些实验,试图找到发散点,但我做不到。我想我的例子太简单了:)由于常量表达式中对未定义行为的不同处理,我有一个错误。我仍然不知道这是否符合标准。不完全相同,但我们可以看到不同的实现如何破坏SFINAE。根据定义推断
constexpr
的编译器应该只在不改变行为的情况下才这样做。@Jens是的,但他们必须遵守“好像”规则。@AaronMcDaid我实际上是在尝试制作一个实例,我已经有一段时间没有看那段代码了,我想确保我得到的详细信息是正确的。这对于特定应用程序中的
constexpr
函数是正确的。除此之外,
constepr
还有其他用途,所以我想说这部分是正确的。(我刚刚删除了我之前对这个答案的评论,因为我还不能用它来创建一个例子,说明行为会因
constepr
的存在而改变。)@AaronMcDaid在这里具有clang和gcc之间的不同行为,其中cos在gcc中标记为constexpr,而不是clang。不过,我在未定义的行为示例中遇到了问题。我从来没有保存过我的转换示例,复制它是一件痛苦的事情。请注意,如果你有一个好的示例,那么请将其包含在你的答案中,以后再复制它永远不会像你认为的那样琐碎。完美。我一直在努力制作一些东西,以证明在clang和g++中都存在依赖于
constexpr
的行为。但这在Clang3.5.0和g++5.2.0中都起到了作用。。。我想这表明在编译时可以检测给定函数是否为
constexpr
。虽然这看起来很酷,但这意味着推断
constexpr
会很危险,因为它会改变这些测试的结果。最后,现在我明白了,我真的不喜欢这个。我认为这应该给出一个错误-如果最好的重载不是
constexpr
,那么如果在需要常量表达式的上下文中调用它,则应该有一个错误。(以我的拙见,刚刚在最后几分钟形成)@AaronMcDaid这个错误是在直接上下文中出现的,所以我们得到了一个替换