C++ constexpr inheriting constructor

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
12
down vote

favorite
3












The following code compiles with GCC 8.2 but not with Clang 6.0.1:



// A struct named Foo.
struct Foo

// Data member of type 'int'.
int val;

// Default constructor (constexpr).
constexpr Foo() noexcept : val(0)
;

// A struct named Bar.
struct Bar : Foo

// Make use of the constructors declared in Foo.
using Foo::Foo;

// A constructor taking an object of type Foo.
// COMMENTING THIS CONSTRUCTOR SOLVE THE COMPILATION ISSUE.
constexpr Bar(Foo const obj) noexcept : Foo(obj)
;


// A struct named Test.
struct Test

// Data member of type 'Bar'.
Bar bar;

// A defaulted default constructor.
constexpr Test() noexcept = default;
;


// Main function.
int main() return 0;


Clang fails with the following message:




error: defaulted definition of default constructor is not constexpr

constexpr Test() noexcept = default;




I would like to understand why Clang is rejecting this code.










share|improve this question



















  • 2




    You forgot to provide a default constructor to Bar (which, however, you're using in Test). Providing an argument to Bar int Test() or alternatively providing a default constructor for Bar should both fix the problem. Why however this compiles with G++ I don't understand. (BTW, it doesn't with gcc 7.3.0 and below)
    – muXXmit2X
    Aug 15 at 5:24











  • @muXXmit2X Possibly C++17 did remove the limitation of not inheriting default constructors (see answer by divinias, "could not find")?
    – Aconcagua
    Aug 15 at 6:03










  • This is interesting because a simplified version of this works you have to go way back to clang 3.8.1 for this to not work ... but adding constexpr into mix breaks the simplified version
    – Shafik Yaghmour
    Aug 15 at 7:47














up vote
12
down vote

favorite
3












The following code compiles with GCC 8.2 but not with Clang 6.0.1:



// A struct named Foo.
struct Foo

// Data member of type 'int'.
int val;

// Default constructor (constexpr).
constexpr Foo() noexcept : val(0)
;

// A struct named Bar.
struct Bar : Foo

// Make use of the constructors declared in Foo.
using Foo::Foo;

// A constructor taking an object of type Foo.
// COMMENTING THIS CONSTRUCTOR SOLVE THE COMPILATION ISSUE.
constexpr Bar(Foo const obj) noexcept : Foo(obj)
;


// A struct named Test.
struct Test

// Data member of type 'Bar'.
Bar bar;

// A defaulted default constructor.
constexpr Test() noexcept = default;
;


// Main function.
int main() return 0;


Clang fails with the following message:




error: defaulted definition of default constructor is not constexpr

constexpr Test() noexcept = default;




I would like to understand why Clang is rejecting this code.










share|improve this question



















  • 2




    You forgot to provide a default constructor to Bar (which, however, you're using in Test). Providing an argument to Bar int Test() or alternatively providing a default constructor for Bar should both fix the problem. Why however this compiles with G++ I don't understand. (BTW, it doesn't with gcc 7.3.0 and below)
    – muXXmit2X
    Aug 15 at 5:24











  • @muXXmit2X Possibly C++17 did remove the limitation of not inheriting default constructors (see answer by divinias, "could not find")?
    – Aconcagua
    Aug 15 at 6:03










  • This is interesting because a simplified version of this works you have to go way back to clang 3.8.1 for this to not work ... but adding constexpr into mix breaks the simplified version
    – Shafik Yaghmour
    Aug 15 at 7:47












up vote
12
down vote

favorite
3









up vote
12
down vote

favorite
3






3





The following code compiles with GCC 8.2 but not with Clang 6.0.1:



// A struct named Foo.
struct Foo

// Data member of type 'int'.
int val;

// Default constructor (constexpr).
constexpr Foo() noexcept : val(0)
;

// A struct named Bar.
struct Bar : Foo

// Make use of the constructors declared in Foo.
using Foo::Foo;

// A constructor taking an object of type Foo.
// COMMENTING THIS CONSTRUCTOR SOLVE THE COMPILATION ISSUE.
constexpr Bar(Foo const obj) noexcept : Foo(obj)
;


// A struct named Test.
struct Test

// Data member of type 'Bar'.
Bar bar;

// A defaulted default constructor.
constexpr Test() noexcept = default;
;


// Main function.
int main() return 0;


Clang fails with the following message:




error: defaulted definition of default constructor is not constexpr

constexpr Test() noexcept = default;




I would like to understand why Clang is rejecting this code.










share|improve this question















The following code compiles with GCC 8.2 but not with Clang 6.0.1:



// A struct named Foo.
struct Foo

// Data member of type 'int'.
int val;

// Default constructor (constexpr).
constexpr Foo() noexcept : val(0)
;

// A struct named Bar.
struct Bar : Foo

// Make use of the constructors declared in Foo.
using Foo::Foo;

// A constructor taking an object of type Foo.
// COMMENTING THIS CONSTRUCTOR SOLVE THE COMPILATION ISSUE.
constexpr Bar(Foo const obj) noexcept : Foo(obj)
;


// A struct named Test.
struct Test

// Data member of type 'Bar'.
Bar bar;

// A defaulted default constructor.
constexpr Test() noexcept = default;
;


// Main function.
int main() return 0;


Clang fails with the following message:




error: defaulted definition of default constructor is not constexpr

constexpr Test() noexcept = default;




I would like to understand why Clang is rejecting this code.







c++ language-lawyer constexpr clang++ default-constructor






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Aug 15 at 7:43









Shafik Yaghmour

118k23296492




118k23296492










asked Aug 15 at 4:45









Ankur deDev

1156




1156







  • 2




    You forgot to provide a default constructor to Bar (which, however, you're using in Test). Providing an argument to Bar int Test() or alternatively providing a default constructor for Bar should both fix the problem. Why however this compiles with G++ I don't understand. (BTW, it doesn't with gcc 7.3.0 and below)
    – muXXmit2X
    Aug 15 at 5:24











  • @muXXmit2X Possibly C++17 did remove the limitation of not inheriting default constructors (see answer by divinias, "could not find")?
    – Aconcagua
    Aug 15 at 6:03










  • This is interesting because a simplified version of this works you have to go way back to clang 3.8.1 for this to not work ... but adding constexpr into mix breaks the simplified version
    – Shafik Yaghmour
    Aug 15 at 7:47












  • 2




    You forgot to provide a default constructor to Bar (which, however, you're using in Test). Providing an argument to Bar int Test() or alternatively providing a default constructor for Bar should both fix the problem. Why however this compiles with G++ I don't understand. (BTW, it doesn't with gcc 7.3.0 and below)
    – muXXmit2X
    Aug 15 at 5:24











  • @muXXmit2X Possibly C++17 did remove the limitation of not inheriting default constructors (see answer by divinias, "could not find")?
    – Aconcagua
    Aug 15 at 6:03










  • This is interesting because a simplified version of this works you have to go way back to clang 3.8.1 for this to not work ... but adding constexpr into mix breaks the simplified version
    – Shafik Yaghmour
    Aug 15 at 7:47







2




2




You forgot to provide a default constructor to Bar (which, however, you're using in Test). Providing an argument to Bar int Test() or alternatively providing a default constructor for Bar should both fix the problem. Why however this compiles with G++ I don't understand. (BTW, it doesn't with gcc 7.3.0 and below)
– muXXmit2X
Aug 15 at 5:24





You forgot to provide a default constructor to Bar (which, however, you're using in Test). Providing an argument to Bar int Test() or alternatively providing a default constructor for Bar should both fix the problem. Why however this compiles with G++ I don't understand. (BTW, it doesn't with gcc 7.3.0 and below)
– muXXmit2X
Aug 15 at 5:24













@muXXmit2X Possibly C++17 did remove the limitation of not inheriting default constructors (see answer by divinias, "could not find")?
– Aconcagua
Aug 15 at 6:03




@muXXmit2X Possibly C++17 did remove the limitation of not inheriting default constructors (see answer by divinias, "could not find")?
– Aconcagua
Aug 15 at 6:03












This is interesting because a simplified version of this works you have to go way back to clang 3.8.1 for this to not work ... but adding constexpr into mix breaks the simplified version
– Shafik Yaghmour
Aug 15 at 7:47




This is interesting because a simplified version of this works you have to go way back to clang 3.8.1 for this to not work ... but adding constexpr into mix breaks the simplified version
– Shafik Yaghmour
Aug 15 at 7:47












2 Answers
2






active

oldest

votes

















up vote
5
down vote



accepted










It looks like clang is relying on pre C++17 wording from C++14 section [class.inhctor]p3:




For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class. Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template ([temp.over.link]) in the complete class where the using-declaration appears. [ Note: Default arguments are not inherited. An exception-specification is implied as specified in [except.spec]. — end note ]




So in C++14:



using Foo::Foo;


means Bar does not inherit Foo's default constructor and Bar does not have a default constructor since it is inhibited by your declaration of:



constexpr Bar(Foo const obj) noexcept : Foo(obj) 


Adding a default constructor to Bar fixes the problem see it live:



constexpr Bar() = default ;


The wording was changed in C++17 with the paper p0136r1: Rewording inheriting constructors (core issue 1941 et al) which was can see was accepted from Changes between C++14 and C++17 DIS




The following papers were moved at committee meetings, but their contents are too specific to call out as separate features: N3922, N4089, N4258, N4261, N4268, N4277, N4285, P0017R1, P0031R0, P0033R1, P0074R0, P0136R1, P0250R3, P0270R3, P0283R2, P0296R2, P0418R2, P0503R0, P0509R1, P0513R0, P0516R0, P0517R0, P0558R1, P0599R1, P0607R0, P0612R0




we can see p0136r1 removed [class.inhctor]:




Remove 12.9 class.inhctor, "Inheriting constructors".




I don't see any wording in p0136r1 that would restrict this case any more. The list of defect reports does not specifically cover this case but the wording changes seem consistent.



So it looks like gcc is correct here and we have a potential clang bug.



gcc 7 release notes



We also obtain a diagnostic in gcc pre 7.x (see it live). If we look at the gcc 7 release notes we see:




The default semantics of inherited constructors has changed in all modes, following P0136. Essentially, overload resolution happens as if calling the inherited constructor directly, and the compiler fills in construction of the other bases and members as needed. Most uses should not need any changes. The old behavior can be restored with -fno-new-inheriting-ctors, or -fabi-version less than 11.




Which seems to confirm the initial conclusion. If we use -fno-new-inheriting-ctors with a slightly modified version of your program it no longer compiles which backs up this was changed with P0136.






share|improve this answer






















  • Seems like a big change and no specific defect report make me wary if this was intended or not.
    – Shafik Yaghmour
    Aug 15 at 7:11










  • Thanks for your answer, I have filled a bug report here
    – Ankur deDev
    Aug 23 at 5:26

















up vote
5
down vote













In C++14, default constructors can not be inherited.



§12.9 [class.inhctor] (emphasis mine)




3 For each non-template constructor in the candidate set of
inherited constructors other than a constructor having no parameters
or a copy/move constructor having a single parameter,
a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class. ...




This basically means, that for your class Bar, the ctor will be implicitly defined - and means using Foo::Foo is not doing anything meaningful.



However, as you are having a separate constructor for Bar, this prevents the implicit definition of a default constructor.



The reason this works when you comment out your separate constexpr Bar(Foo const obj) ctor is because of




5 [ Note: Default and copy/move constructors may be implicitly
declared as specified in 12.1 and 12.8. —end note ]




§12.1/5 [class.ctor]




... If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
implicitly-defined default constructor is constexpr. ...




So, the implicitly declared constructor is declared as constexpr, which makes your code work and compile as expected.



You can remedy the issue by just explicitly defaulting the default ctor like this:



constexpr Bar() noexcept = default;


You can also take a look at Constexpr class: Inheritance?



The problem there is a bit different, but very similar to what you are seeing.



Sadly, I am unable to find the relevant parts in the C++17 standard. I assume the reasoning is the same, but can't find the reference to be 100% sure.






share|improve this answer




















  • Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
    – Ankur deDev
    Aug 15 at 5:49










Your Answer





StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51853091%2fc-constexpr-inheriting-constructor%23new-answer', 'question_page');

);

Post as a guest






























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
5
down vote



accepted










It looks like clang is relying on pre C++17 wording from C++14 section [class.inhctor]p3:




For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class. Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template ([temp.over.link]) in the complete class where the using-declaration appears. [ Note: Default arguments are not inherited. An exception-specification is implied as specified in [except.spec]. — end note ]




So in C++14:



using Foo::Foo;


means Bar does not inherit Foo's default constructor and Bar does not have a default constructor since it is inhibited by your declaration of:



constexpr Bar(Foo const obj) noexcept : Foo(obj) 


Adding a default constructor to Bar fixes the problem see it live:



constexpr Bar() = default ;


The wording was changed in C++17 with the paper p0136r1: Rewording inheriting constructors (core issue 1941 et al) which was can see was accepted from Changes between C++14 and C++17 DIS




The following papers were moved at committee meetings, but their contents are too specific to call out as separate features: N3922, N4089, N4258, N4261, N4268, N4277, N4285, P0017R1, P0031R0, P0033R1, P0074R0, P0136R1, P0250R3, P0270R3, P0283R2, P0296R2, P0418R2, P0503R0, P0509R1, P0513R0, P0516R0, P0517R0, P0558R1, P0599R1, P0607R0, P0612R0




we can see p0136r1 removed [class.inhctor]:




Remove 12.9 class.inhctor, "Inheriting constructors".




I don't see any wording in p0136r1 that would restrict this case any more. The list of defect reports does not specifically cover this case but the wording changes seem consistent.



So it looks like gcc is correct here and we have a potential clang bug.



gcc 7 release notes



We also obtain a diagnostic in gcc pre 7.x (see it live). If we look at the gcc 7 release notes we see:




The default semantics of inherited constructors has changed in all modes, following P0136. Essentially, overload resolution happens as if calling the inherited constructor directly, and the compiler fills in construction of the other bases and members as needed. Most uses should not need any changes. The old behavior can be restored with -fno-new-inheriting-ctors, or -fabi-version less than 11.




Which seems to confirm the initial conclusion. If we use -fno-new-inheriting-ctors with a slightly modified version of your program it no longer compiles which backs up this was changed with P0136.






share|improve this answer






















  • Seems like a big change and no specific defect report make me wary if this was intended or not.
    – Shafik Yaghmour
    Aug 15 at 7:11










  • Thanks for your answer, I have filled a bug report here
    – Ankur deDev
    Aug 23 at 5:26














up vote
5
down vote



accepted










It looks like clang is relying on pre C++17 wording from C++14 section [class.inhctor]p3:




For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class. Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template ([temp.over.link]) in the complete class where the using-declaration appears. [ Note: Default arguments are not inherited. An exception-specification is implied as specified in [except.spec]. — end note ]




So in C++14:



using Foo::Foo;


means Bar does not inherit Foo's default constructor and Bar does not have a default constructor since it is inhibited by your declaration of:



constexpr Bar(Foo const obj) noexcept : Foo(obj) 


Adding a default constructor to Bar fixes the problem see it live:



constexpr Bar() = default ;


The wording was changed in C++17 with the paper p0136r1: Rewording inheriting constructors (core issue 1941 et al) which was can see was accepted from Changes between C++14 and C++17 DIS




The following papers were moved at committee meetings, but their contents are too specific to call out as separate features: N3922, N4089, N4258, N4261, N4268, N4277, N4285, P0017R1, P0031R0, P0033R1, P0074R0, P0136R1, P0250R3, P0270R3, P0283R2, P0296R2, P0418R2, P0503R0, P0509R1, P0513R0, P0516R0, P0517R0, P0558R1, P0599R1, P0607R0, P0612R0




we can see p0136r1 removed [class.inhctor]:




Remove 12.9 class.inhctor, "Inheriting constructors".




I don't see any wording in p0136r1 that would restrict this case any more. The list of defect reports does not specifically cover this case but the wording changes seem consistent.



So it looks like gcc is correct here and we have a potential clang bug.



gcc 7 release notes



We also obtain a diagnostic in gcc pre 7.x (see it live). If we look at the gcc 7 release notes we see:




The default semantics of inherited constructors has changed in all modes, following P0136. Essentially, overload resolution happens as if calling the inherited constructor directly, and the compiler fills in construction of the other bases and members as needed. Most uses should not need any changes. The old behavior can be restored with -fno-new-inheriting-ctors, or -fabi-version less than 11.




Which seems to confirm the initial conclusion. If we use -fno-new-inheriting-ctors with a slightly modified version of your program it no longer compiles which backs up this was changed with P0136.






share|improve this answer






















  • Seems like a big change and no specific defect report make me wary if this was intended or not.
    – Shafik Yaghmour
    Aug 15 at 7:11










  • Thanks for your answer, I have filled a bug report here
    – Ankur deDev
    Aug 23 at 5:26












up vote
5
down vote



accepted







up vote
5
down vote



accepted






It looks like clang is relying on pre C++17 wording from C++14 section [class.inhctor]p3:




For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class. Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template ([temp.over.link]) in the complete class where the using-declaration appears. [ Note: Default arguments are not inherited. An exception-specification is implied as specified in [except.spec]. — end note ]




So in C++14:



using Foo::Foo;


means Bar does not inherit Foo's default constructor and Bar does not have a default constructor since it is inhibited by your declaration of:



constexpr Bar(Foo const obj) noexcept : Foo(obj) 


Adding a default constructor to Bar fixes the problem see it live:



constexpr Bar() = default ;


The wording was changed in C++17 with the paper p0136r1: Rewording inheriting constructors (core issue 1941 et al) which was can see was accepted from Changes between C++14 and C++17 DIS




The following papers were moved at committee meetings, but their contents are too specific to call out as separate features: N3922, N4089, N4258, N4261, N4268, N4277, N4285, P0017R1, P0031R0, P0033R1, P0074R0, P0136R1, P0250R3, P0270R3, P0283R2, P0296R2, P0418R2, P0503R0, P0509R1, P0513R0, P0516R0, P0517R0, P0558R1, P0599R1, P0607R0, P0612R0




we can see p0136r1 removed [class.inhctor]:




Remove 12.9 class.inhctor, "Inheriting constructors".




I don't see any wording in p0136r1 that would restrict this case any more. The list of defect reports does not specifically cover this case but the wording changes seem consistent.



So it looks like gcc is correct here and we have a potential clang bug.



gcc 7 release notes



We also obtain a diagnostic in gcc pre 7.x (see it live). If we look at the gcc 7 release notes we see:




The default semantics of inherited constructors has changed in all modes, following P0136. Essentially, overload resolution happens as if calling the inherited constructor directly, and the compiler fills in construction of the other bases and members as needed. Most uses should not need any changes. The old behavior can be restored with -fno-new-inheriting-ctors, or -fabi-version less than 11.




Which seems to confirm the initial conclusion. If we use -fno-new-inheriting-ctors with a slightly modified version of your program it no longer compiles which backs up this was changed with P0136.






share|improve this answer














It looks like clang is relying on pre C++17 wording from C++14 section [class.inhctor]p3:




For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the complete class where the using-declaration appears or the constructor would be a default, copy, or move constructor for that class. Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template ([temp.over.link]) in the complete class where the using-declaration appears. [ Note: Default arguments are not inherited. An exception-specification is implied as specified in [except.spec]. — end note ]




So in C++14:



using Foo::Foo;


means Bar does not inherit Foo's default constructor and Bar does not have a default constructor since it is inhibited by your declaration of:



constexpr Bar(Foo const obj) noexcept : Foo(obj) 


Adding a default constructor to Bar fixes the problem see it live:



constexpr Bar() = default ;


The wording was changed in C++17 with the paper p0136r1: Rewording inheriting constructors (core issue 1941 et al) which was can see was accepted from Changes between C++14 and C++17 DIS




The following papers were moved at committee meetings, but their contents are too specific to call out as separate features: N3922, N4089, N4258, N4261, N4268, N4277, N4285, P0017R1, P0031R0, P0033R1, P0074R0, P0136R1, P0250R3, P0270R3, P0283R2, P0296R2, P0418R2, P0503R0, P0509R1, P0513R0, P0516R0, P0517R0, P0558R1, P0599R1, P0607R0, P0612R0




we can see p0136r1 removed [class.inhctor]:




Remove 12.9 class.inhctor, "Inheriting constructors".




I don't see any wording in p0136r1 that would restrict this case any more. The list of defect reports does not specifically cover this case but the wording changes seem consistent.



So it looks like gcc is correct here and we have a potential clang bug.



gcc 7 release notes



We also obtain a diagnostic in gcc pre 7.x (see it live). If we look at the gcc 7 release notes we see:




The default semantics of inherited constructors has changed in all modes, following P0136. Essentially, overload resolution happens as if calling the inherited constructor directly, and the compiler fills in construction of the other bases and members as needed. Most uses should not need any changes. The old behavior can be restored with -fno-new-inheriting-ctors, or -fabi-version less than 11.




Which seems to confirm the initial conclusion. If we use -fno-new-inheriting-ctors with a slightly modified version of your program it no longer compiles which backs up this was changed with P0136.







share|improve this answer














share|improve this answer



share|improve this answer








edited Aug 16 at 4:07

























answered Aug 15 at 6:52









Shafik Yaghmour

118k23296492




118k23296492











  • Seems like a big change and no specific defect report make me wary if this was intended or not.
    – Shafik Yaghmour
    Aug 15 at 7:11










  • Thanks for your answer, I have filled a bug report here
    – Ankur deDev
    Aug 23 at 5:26
















  • Seems like a big change and no specific defect report make me wary if this was intended or not.
    – Shafik Yaghmour
    Aug 15 at 7:11










  • Thanks for your answer, I have filled a bug report here
    – Ankur deDev
    Aug 23 at 5:26















Seems like a big change and no specific defect report make me wary if this was intended or not.
– Shafik Yaghmour
Aug 15 at 7:11




Seems like a big change and no specific defect report make me wary if this was intended or not.
– Shafik Yaghmour
Aug 15 at 7:11












Thanks for your answer, I have filled a bug report here
– Ankur deDev
Aug 23 at 5:26




Thanks for your answer, I have filled a bug report here
– Ankur deDev
Aug 23 at 5:26












up vote
5
down vote













In C++14, default constructors can not be inherited.



§12.9 [class.inhctor] (emphasis mine)




3 For each non-template constructor in the candidate set of
inherited constructors other than a constructor having no parameters
or a copy/move constructor having a single parameter,
a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class. ...




This basically means, that for your class Bar, the ctor will be implicitly defined - and means using Foo::Foo is not doing anything meaningful.



However, as you are having a separate constructor for Bar, this prevents the implicit definition of a default constructor.



The reason this works when you comment out your separate constexpr Bar(Foo const obj) ctor is because of




5 [ Note: Default and copy/move constructors may be implicitly
declared as specified in 12.1 and 12.8. —end note ]




§12.1/5 [class.ctor]




... If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
implicitly-defined default constructor is constexpr. ...




So, the implicitly declared constructor is declared as constexpr, which makes your code work and compile as expected.



You can remedy the issue by just explicitly defaulting the default ctor like this:



constexpr Bar() noexcept = default;


You can also take a look at Constexpr class: Inheritance?



The problem there is a bit different, but very similar to what you are seeing.



Sadly, I am unable to find the relevant parts in the C++17 standard. I assume the reasoning is the same, but can't find the reference to be 100% sure.






share|improve this answer




















  • Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
    – Ankur deDev
    Aug 15 at 5:49














up vote
5
down vote













In C++14, default constructors can not be inherited.



§12.9 [class.inhctor] (emphasis mine)




3 For each non-template constructor in the candidate set of
inherited constructors other than a constructor having no parameters
or a copy/move constructor having a single parameter,
a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class. ...




This basically means, that for your class Bar, the ctor will be implicitly defined - and means using Foo::Foo is not doing anything meaningful.



However, as you are having a separate constructor for Bar, this prevents the implicit definition of a default constructor.



The reason this works when you comment out your separate constexpr Bar(Foo const obj) ctor is because of




5 [ Note: Default and copy/move constructors may be implicitly
declared as specified in 12.1 and 12.8. —end note ]




§12.1/5 [class.ctor]




... If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
implicitly-defined default constructor is constexpr. ...




So, the implicitly declared constructor is declared as constexpr, which makes your code work and compile as expected.



You can remedy the issue by just explicitly defaulting the default ctor like this:



constexpr Bar() noexcept = default;


You can also take a look at Constexpr class: Inheritance?



The problem there is a bit different, but very similar to what you are seeing.



Sadly, I am unable to find the relevant parts in the C++17 standard. I assume the reasoning is the same, but can't find the reference to be 100% sure.






share|improve this answer




















  • Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
    – Ankur deDev
    Aug 15 at 5:49












up vote
5
down vote










up vote
5
down vote









In C++14, default constructors can not be inherited.



§12.9 [class.inhctor] (emphasis mine)




3 For each non-template constructor in the candidate set of
inherited constructors other than a constructor having no parameters
or a copy/move constructor having a single parameter,
a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class. ...




This basically means, that for your class Bar, the ctor will be implicitly defined - and means using Foo::Foo is not doing anything meaningful.



However, as you are having a separate constructor for Bar, this prevents the implicit definition of a default constructor.



The reason this works when you comment out your separate constexpr Bar(Foo const obj) ctor is because of




5 [ Note: Default and copy/move constructors may be implicitly
declared as specified in 12.1 and 12.8. —end note ]




§12.1/5 [class.ctor]




... If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
implicitly-defined default constructor is constexpr. ...




So, the implicitly declared constructor is declared as constexpr, which makes your code work and compile as expected.



You can remedy the issue by just explicitly defaulting the default ctor like this:



constexpr Bar() noexcept = default;


You can also take a look at Constexpr class: Inheritance?



The problem there is a bit different, but very similar to what you are seeing.



Sadly, I am unable to find the relevant parts in the C++17 standard. I assume the reasoning is the same, but can't find the reference to be 100% sure.






share|improve this answer












In C++14, default constructors can not be inherited.



§12.9 [class.inhctor] (emphasis mine)




3 For each non-template constructor in the candidate set of
inherited constructors other than a constructor having no parameters
or a copy/move constructor having a single parameter,
a constructor is
implicitly declared with the same constructor characteristics unless
there is a user-declared constructor with the same signature in the
complete class where the using-declaration appears or the constructor
would be a default, copy, or move constructor for that class. ...




This basically means, that for your class Bar, the ctor will be implicitly defined - and means using Foo::Foo is not doing anything meaningful.



However, as you are having a separate constructor for Bar, this prevents the implicit definition of a default constructor.



The reason this works when you comment out your separate constexpr Bar(Foo const obj) ctor is because of




5 [ Note: Default and copy/move constructors may be implicitly
declared as specified in 12.1 and 12.8. —end note ]




§12.1/5 [class.ctor]




... If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
implicitly-defined default constructor is constexpr. ...




So, the implicitly declared constructor is declared as constexpr, which makes your code work and compile as expected.



You can remedy the issue by just explicitly defaulting the default ctor like this:



constexpr Bar() noexcept = default;


You can also take a look at Constexpr class: Inheritance?



The problem there is a bit different, but very similar to what you are seeing.



Sadly, I am unable to find the relevant parts in the C++17 standard. I assume the reasoning is the same, but can't find the reference to be 100% sure.







share|improve this answer












share|improve this answer



share|improve this answer










answered Aug 15 at 5:45









divinas

52229




52229











  • Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
    – Ankur deDev
    Aug 15 at 5:49
















  • Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
    – Ankur deDev
    Aug 15 at 5:49















Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
– Ankur deDev
Aug 15 at 5:49




Thanks for your answer. My expectation was indeed that the default constructor would be inherited via the using directive. Looking further into that direction the following answer (stackoverflow.com/a/44522990) suggests that C++17 introduced a change on this specific point. It would be great to get this confirmed.
– Ankur deDev
Aug 15 at 5:49

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51853091%2fc-constexpr-inheriting-constructor%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

How to check contact read email or not when send email to Individual?

Bahrain

Postfix configuration issue with fips on centos 7; mailgun relay