[英]Evaluating noexcept specifier before template type deduction
Please see the following code: 请参阅以下代码:
#include <utility>
struct A {
A(int, int) {}
};
struct tag {};
template <class... Args>
struct is_noexcept {
static constexpr bool value = noexcept(A{std::declval<Args>()...});
};
struct B : A {
//#1
template <class... Args>
B(tag, Args&&... args) noexcept(/*Here*/is_noexcept<Args...>::value) :
A{std::forward<Args>(args)...} {}
//#2
B(int x, int y) : A{x, y} {}
};
int main()
{
B x{0, 0};
}
This code seems to be accepted by GCC/Clang, but MSVC 2017 rejects it. 这段代码似乎被GCC / Clang接受,但MSVC 2017拒绝接受。 It seems that MSVC compiler tries to compute the noexcept specifier before understanding that #1 is not an appropriate overload (due to incompatibility between tag
and int
) so should be discarded. 似乎MSVC编译器在理解#1不是适当的重载(由于tag
和int
之间不兼容)之前尝试计算noexcept说明符,因此应该被丢弃。 Thus it tries to evaluate is_noexcept<int>::value
and finds out noexcept(A{std::declval<int>()})
is ill-formed. 因此,它尝试评估is_noexcept<int>::value
并发现noexcept(A{std::declval<int>()})
不正确。 Since this happens not in the immediate context , this is not where SFINAE comes in, so hard error. 由于这不是在紧急情况下发生的,因此这不是SFINAE的用武之地,所以很难发生错误。
(In fact, I'm not pretty sure about this, but I've confirmed that if I put noexcept(A{std::declval<Args>()...})
instead of is_noexcept<Args...>::value
at /*Here*/
to make the failure inside the immediate context, the MSVC compiler happily drops #1 and calls #2. Is this right?) (事实上,我对此并不十分肯定,但我已经确认,如果我把noexcept(A{std::declval<Args>()...})
而不是is_noexcept<Args...>::value
at /*Here*/
为了使直接上下文内部失败,MSVC编译器愉快地丢弃#1并调用#2。这是对的吗?)
I suspect GCC/Clang is right and MSVC is wrong, but which one is correct? 我怀疑GCC / Clang是对的,MSVC是错的,但哪一个是正确的?
This is an MSVC bug. 这是一个MSVC错误。 The rule, as a result of CWG 1330 , in [except.spec]/13 is: 作为CWG 1330的结果, [except.spec] / 13中的规则是:
An exception specification is considered to be needed when: 在以下情况下, 需要考虑异常规范:
- in an expression, the function is the unique lookup result or the selected member of a set of overloaded functions ([basic.lookup], [over.match], [over.over]); 在表达式中,该函数是唯一的查找结果或一组重载函数的选定成员([basic.lookup],[over.match],[over.over]);
- the function is odr-used or, if it appears in an unevaluated operand, would be odr-used if the expression were potentially-evaluated; 该函数是odr-used,或者,如果它出现在未评估的操作数中,如果表达式被潜在评估,则会使用该函数;
- the exception specification is compared to that of another declaration (eg, an explicit specialization or an overriding virtual function); 将异常规范与另一个声明的规范进行比较(例如,显式特化或覆盖虚函数);
- the function is defined; 功能定义; or 要么
- the exception specification is needed for a defaulted special member function that calls the function. 调用该函数的默认特殊成员函数需要异常规范。 [ Note: A defaulted declaration does not require the exception specification of a base member function to be evaluated until the implicit exception specification of the derived function is needed, but an explicit noexcept-specifier needs the implicit exception specification to compare against. [注意:默认声明不需要评估基本成员函数的异常规范,直到需要派生函数的隐式异常规范,但显式noexcept-specifier需要隐式异常规范进行比较。 — end note ] - 结束说明]
The exception specification of a defaulted special member function is evaluated as described above only when needed; 仅在需要时如上所述评估默认特殊成员函数的异常规范; similarly, the noexcept-specifier of a specialization of a function template or member function of a class template is instantiated only when needed. 类似地,仅在需要时实例化函数模板的特化或类模板的成员函数的noexcept-specifier 。
The exception specification of B(tag, Args&&...)
is not needed (we don't satisfy any of those bullets), so it should not be instantiated. 不需要B(tag, Args&&...)
的异常规范(我们不满足任何这些项目符号),因此不应该实例化它。
Note also that substitution failure in the exception specification is not part of the immediate context, and would not be a SFINAE-friendly error. 另请注意,异常规范中的替换失败不是直接上下文的一部分,并且不会是SFINAE友好的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.