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;









46

















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










share|improve this question























  • 6





    Boost fixed this in 1.70. It's also discussed here.

    – interjay
    May 29 at 19:54


















46

















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










share|improve this question























  • 6





    Boost fixed this in 1.70. It's also discussed here.

    – interjay
    May 29 at 19:54














46












46








46


3






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










share|improve this question

















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






share|improve this question
















share|improve this question













share|improve this question




share|improve this question








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













  • 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













1 Answer
1






active

oldest

votes


















59


















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.






share|improve this answer





















  • 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












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
);



);














draft saved

draft discarded
















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









59


















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.






share|improve this answer





















  • 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















59


















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.






share|improve this answer





















  • 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













59














59










59









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.






share|improve this answer














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.







share|improve this answer













share|improve this answer




share|improve this answer










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












  • 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




















draft saved

draft discarded















































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.




draft saved


draft discarded














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





















































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









Popular posts from this blog

Tamil (spriik) Luke uk diar | Nawigatjuun

Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

Where does the image of a data connector as a sharp metal spike originate from?Where does the concept of infected people turning into zombies only after death originate from?Where does the motif of a reanimated human head originate?Where did the notion that Dragons could speak originate?Where does the archetypal image of the 'Grey' alien come from?Where did the suffix '-Man' originate?Where does the notion of being injured or killed by an illusion originate?Where did the term “sophont” originate?Where does the trope of magic spells being driven by advanced technology originate from?Where did the term “the living impaired” originate?