简体   繁体   English

在模板类型推导之前评估noexcept说明符

[英]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不是适当的重载(由于tagint之间不兼容)之前尝试计算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. [注意:默认声明不需要评估基本成员函数的异常规范,直到需要派生函数的隐式异常规范,但显式n​​oexcept-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM