22

The code:

struct T { T() {} };

struct S
{
    T t;

    S() noexcept = default;
};

int main()
{
//    S s;
}

g++ 4.9.2 accepts this with no errors or warnings, however clang 3.6 and 3.7 report for line 7:

error: exception specification of explicitly defaulted default constructor does not match the calculated one

However, if the line S s; is not commented out, g++ 4.9.2 now reports:

noex.cc: In function 'int main()':
noex.cc:12:7: error: use of deleted function 'S::S()'
     S s;
       ^
noex.cc:7:5: note: 'S::S() noexcept' is implicitly deleted because its  exception-specification does not match the implicit exception-specification ''
     S() noexcept = default;
     ^

Which compiler is right for the original code?


Background:

g++ even allows the following to be added to main:

std::cout << std::is_constructible<S>::value << '\n';

which outputs 0. I encountered this problem when using clang to compile some complicated code that made heavy use of templates, SFINAE and noexcept. In that code S and T are template classes; so the behaviour depends on which types S was instantiated with. Clang rejects it with this error for some types, whereas g++ permits it and the SFINAE works based on is_constructible and similar traits.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Because in S constructor you'll get call to T constructor which could throw any exception.Clang is right, I believe – Severin Pappadeux Apr 07 '15 at 03:28
  • 1
    @SeverinPappadeux that's true about the exceptions but the issue seems to be whether the code should be rejected immediately, or whether the effect of `= default` should be to *define as deleted* which g++ seems to be doing. – M.M Apr 07 '15 at 03:32

1 Answers1

23

Depends on the version of the standard you are consulting.

N3337 [dcl.fct.def.default]/p2:

An explicitly-defaulted function [...] may have an explicit exception-specification only if it is compatible (15.4) with the exception-specification on the implicit declaration.

which renders your original code ill-formed.

This was changed by CWG issue 1778 to read (N4296 [dcl.fct.def.default]/p3):

If a function that is explicitly defaulted is declared with an exception-specification that is not compatible (15.4) with the exception specification on the implicit declaration, then

  • if the function is explicitly defaulted on its first declaration, it is defined as deleted;
  • otherwise, the program is ill-formed.

which means that the constructor is now merely defined as deleted. (The above wording incorporated changes made by N4285, a post-C++14 paper making some cleanup changes intended to be purely editorial. The N3936 version is substantively the same.)

Presumably GCC implements CWG1778's resolution, while Clang doesn't.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Which version appeared in published C++14 ? (clang 3.7 still rejects the code with -std=c++14) – M.M Apr 07 '15 at 03:35
  • @MattMcNabb The issue has "C++14" status, so the second version should be in C++14. Note that this is a DR, so it probably will be implemented even in C++11 mode. – T.C. Apr 07 '15 at 03:36
  • @MattMcNabb 4296 is pretty much what was voted as C++14 modulo typos and such – Severin Pappadeux Apr 07 '15 at 03:37
  • @SeverinPappadeux Nah, 4296 has some C++1z stuff. I probably should quote 3936 or 4140. – T.C. Apr 07 '15 at 03:37
  • @T.C. Thank you, didn't know it. I thought 4296 is it because official standard was marked by December 15 (?) 2014 – Severin Pappadeux Apr 07 '15 at 03:40
  • @SeverinPappadeux Completing the ballot on the draft and then working through all the bureaucratic paperwork takes time :) The C++14 draft was voted out of the committee in February 2014. – T.C. Apr 07 '15 at 08:01
  • It seems that CWG1778 was reverted again for c++20: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1286r2.html – craffael Jun 10 '20 at 20:35