mardi 24 juillet 2018

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. 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. Thus it tries to evaluate is_noexcept<int>::value and finds out noexcept(A{std::declval<int>()}) is ill-formed. Since this happens not in the immediate context , this is not where SFINAE comes in, so hard error.

(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?)

I suspect GCC/Clang is right and MSVC is wrong, but which one is correct?

Aucun commentaire:

Enregistrer un commentaire