C++ constexpr inheriting constructor
Clash Royale CLAN TAG#URR8PPP
up vote
12
down vote
favorite
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
add a comment |Â
up vote
12
down vote
favorite
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
2
You forgot to provide a default constructor toBar
(which, however, you're using inTest
). Providing an argument toBar
intTest()
or alternatively providing a default constructor forBar
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
add a comment |Â
up vote
12
down vote
favorite
up vote
12
down vote
favorite
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
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
c++ language-lawyer constexpr clang++ default-constructor
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 toBar
(which, however, you're using inTest
). Providing an argument toBar
intTest()
or alternatively providing a default constructor forBar
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
add a comment |Â
2
You forgot to provide a default constructor toBar
(which, however, you're using inTest
). Providing an argument toBar
intTest()
or alternatively providing a default constructor forBar
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
add a comment |Â
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
.
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
add a comment |Â
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.
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
add a comment |Â
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
.
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
add a comment |Â
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
.
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
add a comment |Â
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
.
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
.
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
add a comment |Â
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
add a comment |Â
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.
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
add a comment |Â
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.
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
add a comment |Â
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.
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.
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
add a comment |Â
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
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
2
You forgot to provide a default constructor to
Bar
(which, however, you're using inTest
). Providing an argument toBar
intTest()
or alternatively providing a default constructor forBar
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