Should this code fail to compile in C++17?“temporary of type 'A' has protected destructor”, but its type is BDoes this code result in a materialized base prvalue, and should it compile?What is a smart pointer and when should I use one?When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?How can I profile C++ code running on Linux?Why should I use a pointer rather than the object itself?Compiling an application for use in highly radioactive environmentsWhat are the new features in C++17?clang 3.9, auto_ptr and boostC++17 code not compiling on Travis with Clang-6.0C++17: explicit conversion function vs explicit constructor + implicit conversions - have the rules changed?C++17 - Binding rvalue reference to non-const lvalue ref
Mutate my DNA sequence
Antonym for “boilerplate” or “cookie-cutter”
Shrinkage priors
instead of pressurizing an entire spacesuit with oxygen could oxygen just pressurize the head and the rest of the body be pressurized with water?
How to define this quick table macro?
Why is a Lockheed MC-130J Commando II creating such a loud droning sound?
My professor has no direction
Rational Number RNG
What do you call this when cats hunch their backs and their fur stands on end?
What can I use for input conversion instead of scanf?
Protecting Seals from Forgery
Why am I having wrong IPs in my DNS?
Print-based debugging
Why is Eastern Switzerland called Suisse orientale in French?
How to discourage mundane play?
Can you put L trominos to fill the figure?
Parents suppressing the teaching
Use of expression "statistically significantly positive"
responsibility for arrangement of elements - Frontend or Backend?
Why do we use the Greek letter μ (Mu) to denote population mean or expected value in probability and statistics
ArcPy UpdateCursor auto pausing after every 1000 records
Can you identify this fighter aircraft?
Why is Robin Hood French in Shrek?
What does exhaust smell on oil and transmission dipstick mean?
Should this code fail to compile in C++17?
“temporary of type 'A' has protected destructor”, but its type is BDoes this code result in a materialized base prvalue, and should it compile?What is a smart pointer and when should I use one?When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?How can I profile C++ code running on Linux?Why should I use a pointer rather than the object itself?Compiling an application for use in highly radioactive environmentsWhat are the new features in C++17?clang 3.9, auto_ptr and boostC++17 code not compiling on Travis with Clang-6.0C++17: explicit conversion function vs explicit constructor + implicit conversions - have the rules changed?C++17 - Binding rvalue reference to non-const lvalue ref
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
I was updating a project to use C++17 and found a few instances where code that followed this pattern was causing a compile error on recent versions of clang:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
void operator()(int) const
;
int main()
boost::variant<int> v = 0;
boost::apply_visitor(vis, v);
Using clang v8.0 in C++17 mode, this fails with the following error:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
However, it compiles cleanly in C++14 mode. I found that if I change the brace initialization vis
to parentheses vis()
, then it compiles correctly in both modes. Every version of gcc that I've tried allows both variants in C++17 mode.
Is this a correct change in behavior from C++14 to C++17, or is this a clang bug? If it is correct, why is it now invalid in C++17 (or maybe it always was, but clang just allows it in earlier standard revisions)?
c++ clang c++17 boost-variant
add a comment
|
I was updating a project to use C++17 and found a few instances where code that followed this pattern was causing a compile error on recent versions of clang:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
void operator()(int) const
;
int main()
boost::variant<int> v = 0;
boost::apply_visitor(vis, v);
Using clang v8.0 in C++17 mode, this fails with the following error:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
However, it compiles cleanly in C++14 mode. I found that if I change the brace initialization vis
to parentheses vis()
, then it compiles correctly in both modes. Every version of gcc that I've tried allows both variants in C++17 mode.
Is this a correct change in behavior from C++14 to C++17, or is this a clang bug? If it is correct, why is it now invalid in C++17 (or maybe it always was, but clang just allows it in earlier standard revisions)?
c++ clang c++17 boost-variant
6
Boost fixed this in 1.70. It's also discussed here.
– interjay
May 29 at 19:54
add a comment
|
I was updating a project to use C++17 and found a few instances where code that followed this pattern was causing a compile error on recent versions of clang:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
void operator()(int) const
;
int main()
boost::variant<int> v = 0;
boost::apply_visitor(vis, v);
Using clang v8.0 in C++17 mode, this fails with the following error:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
However, it compiles cleanly in C++14 mode. I found that if I change the brace initialization vis
to parentheses vis()
, then it compiles correctly in both modes. Every version of gcc that I've tried allows both variants in C++17 mode.
Is this a correct change in behavior from C++14 to C++17, or is this a clang bug? If it is correct, why is it now invalid in C++17 (or maybe it always was, but clang just allows it in earlier standard revisions)?
c++ clang c++17 boost-variant
I was updating a project to use C++17 and found a few instances where code that followed this pattern was causing a compile error on recent versions of clang:
#include <boost/variant.hpp>
struct vis : public boost::static_visitor<void>
void operator()(int) const
;
int main()
boost::variant<int> v = 0;
boost::apply_visitor(vis, v);
Using clang v8.0 in C++17 mode, this fails with the following error:
<source>:11:30: error: temporary of type 'boost::static_visitor<void>' has protected destructor
boost::apply_visitor(vis, v);
^
/opt/compiler-explorer/libs/boost_1_64_0/boost/variant/static_visitor.hpp:53:5: note: declared protected here
~static_visitor() = default;
However, it compiles cleanly in C++14 mode. I found that if I change the brace initialization vis
to parentheses vis()
, then it compiles correctly in both modes. Every version of gcc that I've tried allows both variants in C++17 mode.
Is this a correct change in behavior from C++14 to C++17, or is this a clang bug? If it is correct, why is it now invalid in C++17 (or maybe it always was, but clang just allows it in earlier standard revisions)?
c++ clang c++17 boost-variant
c++ clang c++17 boost-variant
edited May 29 at 19:50
Barry
202k22 gold badges382 silver badges676 bronze badges
202k22 gold badges382 silver badges676 bronze badges
asked May 29 at 19:43
Jason RJason R
6,5292 gold badges37 silver badges63 bronze badges
6,5292 gold badges37 silver badges63 bronze badges
6
Boost fixed this in 1.70. It's also discussed here.
– interjay
May 29 at 19:54
add a comment
|
6
Boost fixed this in 1.70. It's also discussed here.
– interjay
May 29 at 19:54
6
6
Boost fixed this in 1.70. It's also discussed here.
– interjay
May 29 at 19:54
Boost fixed this in 1.70. It's also discussed here.
– interjay
May 29 at 19:54
add a comment
|
1 Answer
1
active
oldest
votes
clang is correct here. Here's a reduced example:
struct B
protected:
B()
;
struct D : B ;
auto d = D;
In C++14, D
is not an aggregate because it has a base class, so D
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.
6
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
2
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
@L.F. No, it does not.D()
being value initialization precedes the new bullet.
– Barry
May 30 at 13:34
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
|
show 4 more comments
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',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56367480%2fshould-this-code-fail-to-compile-in-c17%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
clang is correct here. Here's a reduced example:
struct B
protected:
B()
;
struct D : B ;
auto d = D;
In C++14, D
is not an aggregate because it has a base class, so D
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.
6
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
2
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
@L.F. No, it does not.D()
being value initialization precedes the new bullet.
– Barry
May 30 at 13:34
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
|
show 4 more comments
clang is correct here. Here's a reduced example:
struct B
protected:
B()
;
struct D : B ;
auto d = D;
In C++14, D
is not an aggregate because it has a base class, so D
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.
6
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
2
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
@L.F. No, it does not.D()
being value initialization precedes the new bullet.
– Barry
May 30 at 13:34
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
|
show 4 more comments
clang is correct here. Here's a reduced example:
struct B
protected:
B()
;
struct D : B ;
auto d = D;
In C++14, D
is not an aggregate because it has a base class, so D
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.
clang is correct here. Here's a reduced example:
struct B
protected:
B()
;
struct D : B ;
auto d = D;
In C++14, D
is not an aggregate because it has a base class, so D
is "normal" (non-aggregate) initialization which invokes D
's default constructor, which in turn invokes B
's default constructor. This is fine, because D
has access to B
's default constructor.
In C++17, the definition of aggregate was widened - base classes are now allowed (as long as they're non-virtual
). D
is now an aggregate, which means that D
is aggregate initialization. And in aggregate-initialization, this means that we (the caller) are initializing all the subobjects - including the base class subobject. But we do not have access to B
's constructor (it is protected
), so we cannot invoke it, so it is ill-formed.
Fear not, the fix is easy. Use parentheses:
auto d = D();
This goes back to invoking D
's default constructor as before.
answered May 29 at 19:49
BarryBarry
202k22 gold badges382 silver badges676 bronze badges
202k22 gold badges382 silver badges676 bronze badges
6
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
2
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
@L.F. No, it does not.D()
being value initialization precedes the new bullet.
– Barry
May 30 at 13:34
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
|
show 4 more comments
6
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
2
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
@L.F. No, it does not.D()
being value initialization precedes the new bullet.
– Barry
May 30 at 13:34
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
6
6
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Perfect, that's what I was looking for: the widened definition of aggregate is the culprit.
– Jason R
May 29 at 19:56
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
Is clang right to be right? What is the accessibility context of the subobject initializer? There is a core language issue about that: issue #2244. As a coder, I would prefer that name accessibility checks for dcl.init.aggr/5.1 and dcl.init.aggr/5.2 are done, in both cases, in the context of the aggregate.
– Oliv
May 30 at 6:03
2
2
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
I heard that parentheses and braces are unified in C++20. Does that affect the validity of the fix?
– L. F.
May 30 at 7:16
@L.F. No, it does not.
D()
being value initialization precedes the new bullet.– Barry
May 30 at 13:34
@L.F. No, it does not.
D()
being value initialization precedes the new bullet.– Barry
May 30 at 13:34
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
@Oliv I think clang is right to be right. I don't know what the accessibility direction is.
– Barry
May 30 at 13:36
|
show 4 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56367480%2fshould-this-code-fail-to-compile-in-c17%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
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
Required, but never shown
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
Required, but never shown
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
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
6
Boost fixed this in 1.70. It's also discussed here.
– interjay
May 29 at 19:54