2017-10-17 109 views
7

noexcept在斯科特迈尔斯的‘有效的现代C++’,他给出了以下功能找到一个数组的大小:使用与constexpr功能

template<typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&)[N]) noexcept 
{ 
    return N; 
} 

什么目的‘noexcept’在这里吗?据我了解,noexcept只影响运行时代码的生成 - 但我看不到任何可以在运行时调用此函数而不是编译时的情况?

+0

如果此功能不noexcept,它可能会导致一些类的默认特殊功能的产生不被noexcept,然后导致容器使用悲观的代码,以确保异常安全。在这个[例子](https://godbolt.org/g/BKmM3n)中,'struct x'不是默认可构造的,可能不是人们所期望的。 – Oliv

回答

5

在一般情况下,一个模板标记为constexpr实例化时,可能失去这一地位。如果一组特定的模板参数不允许,那么该资格将被无声地删除,并且生成的函数是一个“常规”函数。

它最有可能这样的规定,教你一个好习惯。虽然这是真的,一个consexpr功能隐含地假设不抛出,如果函数的constexpr状态被删除,但仍然无法与正确noexcept规格干扰。当它被用作输入到noexcept()运算符的表达式的一部分时。

,如果不是因为这样的定义,它会扭曲的,在他们的noexcept()应用程序中使用它的功能异常规范。因为它被认为可能在没有规范的情况下投掷。

由于noexcept()操作是在编译时计算过,这不是关于代码生成的所有(如你的话来说)。这更多的是语义正确性的问题,类似于const正确性。

+0

问题在于常量表达式无论如何都被认为是不抛出。所以应用noexcept运营商ARRAYSIZE的调用将返回true,即使没有'noexcept'预选赛:http://coliru.stacked-crooked.com/a/991fcd1cb348baef。所以它不被认为是“没有规范就可能抛出”。 –

+0

@NirFriedman - (A)如果实例化不允许,可以隐式地撤销模板函数constexpr状态。不管这个过分简单的情况。 (B)这就是为什么迈尔斯想要强调一般原则的原因,默认情况下,这个原则是“不排除”正确的。 – StoryTeller

+0

当然,我并不反对你的评论,但是你应该说这是一个很好的习惯,等等。你的实际答案表明它可能干扰正确的'noexcept'规范,但事实并非如此。用户在这里问“这里** noexcept **的目的是什么**”。我不认为你在这里给出的答案是正确的,因为'noexcept'运算符无论如何都返回true。如果你仍然认为这是正确的,我希望看到一个例子,从'arraySize'移除'noexcept'会干扰另一个'noexcept'规范的正确性。 –

0

但我看不到任何情况下,可以在运行时调用此函数而不是编译时间?

例如,简单地用:

int a[42]; 

std::cout << arraySize(a); 

我们不是一个常量表达式。

要强制constexpr,你必须使用类似:

int a[42]; 
constexpr auto size = arraySize(a); 
std::cout << size; 
+0

'std :: cout << arraySize(a);'not编译为'std :: cout << 42;'? –

+0

它可以通过As-If规则(即使您删除'constexpr'顺便说一句),但它不是必需的。 – Jarod42

+0

我认为'arraySize(a)'是一个常量表达式。某件事是否是一个常量表达式并不取决于它所分配的内容;只是影响它是否确实在编译时被保证进行评估。无论如何,正如我上面提到的那样,'noexcept(arraySize(a))'返回true。 –