Compilation error when using empty list initialization constructor in C++17
I ran into a weird problem when trying to move to C++17. The problem is that something (and I'm not sure what) changed in C++17 that made list-initialization work differently in the case of a default constructor. I tried to search https://en.cppreference.com/w/cpp/language/list_initialization for more info, but I didn't find anything that looks relevant.
Does someone know the reason the code below compiles in C++14 but not in C++17 when calling B{}
instead of B()
?
(I tried it in both gcc 8.2 and 7.3 and icc 19)
struct A{
protected:
A() {}
};
struct B : public A {};
B f(){
return B(); //compilation OK
//return B{}; //compilation error
}
c++ c++17 list-initialization
New contributor
|
show 17 more comments
I ran into a weird problem when trying to move to C++17. The problem is that something (and I'm not sure what) changed in C++17 that made list-initialization work differently in the case of a default constructor. I tried to search https://en.cppreference.com/w/cpp/language/list_initialization for more info, but I didn't find anything that looks relevant.
Does someone know the reason the code below compiles in C++14 but not in C++17 when calling B{}
instead of B()
?
(I tried it in both gcc 8.2 and 7.3 and icc 19)
struct A{
protected:
A() {}
};
struct B : public A {};
B f(){
return B(); //compilation OK
//return B{}; //compilation error
}
c++ c++17 list-initialization
New contributor
1
Try adding this flag:-std=c++0x
. I am not sure though.
– DimChtz
2 days ago
1
@DimChtz That changes the standard to C++11 draft, on compilers old enough to support its pre-standardisation name. Probably not helpful.
– Lightness Races in Orbit
2 days ago
What are you expecting A to be? Doesn't look valid to me. {} is an initializer or scope wrapper, () is use to wrap parameters and parentheses. In your case A() is a constructor with nothing to initialise. Your compilation error is correct, return B() returns an object with nothing in it, whilst calling the empty constructor first.
– SPlatten
2 days ago
1
@SPlatten Well, C++ isn't an OO language, so that's reasonable :)
– Lightness Races in Orbit
2 days ago
3
@SPlatten Bjarne may originally have called it "C With Classes", and implied that this makes it OO, but he was wrong. Okay, I'll be charitable and change that to say that the generally-accepted terminology has shifted in the interim, as things were added and times changed. C++ is multi-paradigm, supporting class-based OO as an option but alternatives too (imperative, concurrent, template metaprogramming). Java has elements of some of these things but is fundamentally OO in a way that C++ never was.
– Lightness Races in Orbit
2 days ago
|
show 17 more comments
I ran into a weird problem when trying to move to C++17. The problem is that something (and I'm not sure what) changed in C++17 that made list-initialization work differently in the case of a default constructor. I tried to search https://en.cppreference.com/w/cpp/language/list_initialization for more info, but I didn't find anything that looks relevant.
Does someone know the reason the code below compiles in C++14 but not in C++17 when calling B{}
instead of B()
?
(I tried it in both gcc 8.2 and 7.3 and icc 19)
struct A{
protected:
A() {}
};
struct B : public A {};
B f(){
return B(); //compilation OK
//return B{}; //compilation error
}
c++ c++17 list-initialization
New contributor
I ran into a weird problem when trying to move to C++17. The problem is that something (and I'm not sure what) changed in C++17 that made list-initialization work differently in the case of a default constructor. I tried to search https://en.cppreference.com/w/cpp/language/list_initialization for more info, but I didn't find anything that looks relevant.
Does someone know the reason the code below compiles in C++14 but not in C++17 when calling B{}
instead of B()
?
(I tried it in both gcc 8.2 and 7.3 and icc 19)
struct A{
protected:
A() {}
};
struct B : public A {};
B f(){
return B(); //compilation OK
//return B{}; //compilation error
}
c++ c++17 list-initialization
c++ c++17 list-initialization
New contributor
New contributor
edited yesterday
TylerH
15.4k105067
15.4k105067
New contributor
asked 2 days ago
RyAraziRyArazi
967
967
New contributor
New contributor
1
Try adding this flag:-std=c++0x
. I am not sure though.
– DimChtz
2 days ago
1
@DimChtz That changes the standard to C++11 draft, on compilers old enough to support its pre-standardisation name. Probably not helpful.
– Lightness Races in Orbit
2 days ago
What are you expecting A to be? Doesn't look valid to me. {} is an initializer or scope wrapper, () is use to wrap parameters and parentheses. In your case A() is a constructor with nothing to initialise. Your compilation error is correct, return B() returns an object with nothing in it, whilst calling the empty constructor first.
– SPlatten
2 days ago
1
@SPlatten Well, C++ isn't an OO language, so that's reasonable :)
– Lightness Races in Orbit
2 days ago
3
@SPlatten Bjarne may originally have called it "C With Classes", and implied that this makes it OO, but he was wrong. Okay, I'll be charitable and change that to say that the generally-accepted terminology has shifted in the interim, as things were added and times changed. C++ is multi-paradigm, supporting class-based OO as an option but alternatives too (imperative, concurrent, template metaprogramming). Java has elements of some of these things but is fundamentally OO in a way that C++ never was.
– Lightness Races in Orbit
2 days ago
|
show 17 more comments
1
Try adding this flag:-std=c++0x
. I am not sure though.
– DimChtz
2 days ago
1
@DimChtz That changes the standard to C++11 draft, on compilers old enough to support its pre-standardisation name. Probably not helpful.
– Lightness Races in Orbit
2 days ago
What are you expecting A to be? Doesn't look valid to me. {} is an initializer or scope wrapper, () is use to wrap parameters and parentheses. In your case A() is a constructor with nothing to initialise. Your compilation error is correct, return B() returns an object with nothing in it, whilst calling the empty constructor first.
– SPlatten
2 days ago
1
@SPlatten Well, C++ isn't an OO language, so that's reasonable :)
– Lightness Races in Orbit
2 days ago
3
@SPlatten Bjarne may originally have called it "C With Classes", and implied that this makes it OO, but he was wrong. Okay, I'll be charitable and change that to say that the generally-accepted terminology has shifted in the interim, as things were added and times changed. C++ is multi-paradigm, supporting class-based OO as an option but alternatives too (imperative, concurrent, template metaprogramming). Java has elements of some of these things but is fundamentally OO in a way that C++ never was.
– Lightness Races in Orbit
2 days ago
1
1
Try adding this flag:
-std=c++0x
. I am not sure though.– DimChtz
2 days ago
Try adding this flag:
-std=c++0x
. I am not sure though.– DimChtz
2 days ago
1
1
@DimChtz That changes the standard to C++11 draft, on compilers old enough to support its pre-standardisation name. Probably not helpful.
– Lightness Races in Orbit
2 days ago
@DimChtz That changes the standard to C++11 draft, on compilers old enough to support its pre-standardisation name. Probably not helpful.
– Lightness Races in Orbit
2 days ago
What are you expecting A to be? Doesn't look valid to me. {} is an initializer or scope wrapper, () is use to wrap parameters and parentheses. In your case A() is a constructor with nothing to initialise. Your compilation error is correct, return B() returns an object with nothing in it, whilst calling the empty constructor first.
– SPlatten
2 days ago
What are you expecting A to be? Doesn't look valid to me. {} is an initializer or scope wrapper, () is use to wrap parameters and parentheses. In your case A() is a constructor with nothing to initialise. Your compilation error is correct, return B() returns an object with nothing in it, whilst calling the empty constructor first.
– SPlatten
2 days ago
1
1
@SPlatten Well, C++ isn't an OO language, so that's reasonable :)
– Lightness Races in Orbit
2 days ago
@SPlatten Well, C++ isn't an OO language, so that's reasonable :)
– Lightness Races in Orbit
2 days ago
3
3
@SPlatten Bjarne may originally have called it "C With Classes", and implied that this makes it OO, but he was wrong. Okay, I'll be charitable and change that to say that the generally-accepted terminology has shifted in the interim, as things were added and times changed. C++ is multi-paradigm, supporting class-based OO as an option but alternatives too (imperative, concurrent, template metaprogramming). Java has elements of some of these things but is fundamentally OO in a way that C++ never was.
– Lightness Races in Orbit
2 days ago
@SPlatten Bjarne may originally have called it "C With Classes", and implied that this makes it OO, but he was wrong. Okay, I'll be charitable and change that to say that the generally-accepted terminology has shifted in the interim, as things were added and times changed. C++ is multi-paradigm, supporting class-based OO as an option but alternatives too (imperative, concurrent, template metaprogramming). Java has elements of some of these things but is fundamentally OO in a way that C++ never was.
– Lightness Races in Orbit
2 days ago
|
show 17 more comments
3 Answers
3
active
oldest
votes
In C++14, the definition of aggregate was:
An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
Hence, B
is not an aggregate. As a result B{}
is surely not aggregate initialization, and B{}
and B()
end up meaning the same thing. They both just invoke B
's default constructor.
However, in C++17, the definition of aggregate was changed to:
An aggregate is an array or a class with
- no user-provided, explicit, or inherited constructors ([class.ctor]),
- no private or protected non-static data members (Clause [class.access]),
- no virtual functions, and
no virtual, private, or protected base classes ([class.mi]).
[ Note: Aggregate initialization does not allow accessing protected and private base class' members or constructors. — end note ]
The restriction is no longer on any base classes, but just on virtual/private/protected ones. But B
has a public base class. It is now an aggregate! And C++17 aggregate initialization does allow for initializing base class subobjects.
In particular, B{}
is aggregate initialization where we just don't provide an initializer for any subobject. But the first (and only) subobject is an A
, which we're trying to initialize from {}
(during aggregate initialization, any subobject without an explicit initializer is copy-initialized from {}
), which we can't do because A
's constructor is protected and we are not a friend (see also, the quoted note).
Note that, just for fun, in C++20 the definition of aggregate will change again.
1
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class withB{A{}}
, and if such initializer is missing, an "empty initializer" is added for theA
subobject, and not one for each members ofA
, as I would have thought before.
– Holt
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
add a comment |
From my understanding of https://en.cppreference.com/w/cpp/language/value_initialization
B{}
does an aggregate_initialization,
and since C++17:
The effects of aggregate initialization are:
- Each direct public base, (since C++17) [..] is copy-initialized from the corresponding clause of the initializer list.
and in our case:
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
So B{/*constructor of A*/}
need to construct base class A, which is protected...
add a comment |
The final draft of C++17 n4659 has a compatibility section which contains the changes with respect to previous versions.
C.4.4 Clause 11: declarators [diff.cpp14.decl]
11.6.1
Change: Definition of an aggregate is extended to apply to user-defined types with base classes.
Rationale: To increase
convenience of aggregate initialization.
Effect on original feature:
Valid C++ 2014 code may fail to compile or produce different results
in this International Standard; initialization from an empty
initializer list will perform aggregate initialization instead of
invoking a default constructor for the affected types:
struct derived;
struct base {
friend struct derived;
private:
base();
};
struct derived : base {};
derived d1{}; // Error. The code was well-formed before.
derived d2; // still OK
I compiled the above example code with -std=c++14
and it compiled but failed to compile with -std=c++17
.
I believe that could be the reason why the code in the OP fails with B{}
but succeeds with B()
.
add a comment |
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/3.0/"u003ecc by-sa 3.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
});
}
});
RyArazi is a new contributor. Be nice, and check out our Code of Conduct.
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%2f54092781%2fcompilation-error-when-using-empty-list-initialization-constructor-in-c17%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
In C++14, the definition of aggregate was:
An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
Hence, B
is not an aggregate. As a result B{}
is surely not aggregate initialization, and B{}
and B()
end up meaning the same thing. They both just invoke B
's default constructor.
However, in C++17, the definition of aggregate was changed to:
An aggregate is an array or a class with
- no user-provided, explicit, or inherited constructors ([class.ctor]),
- no private or protected non-static data members (Clause [class.access]),
- no virtual functions, and
no virtual, private, or protected base classes ([class.mi]).
[ Note: Aggregate initialization does not allow accessing protected and private base class' members or constructors. — end note ]
The restriction is no longer on any base classes, but just on virtual/private/protected ones. But B
has a public base class. It is now an aggregate! And C++17 aggregate initialization does allow for initializing base class subobjects.
In particular, B{}
is aggregate initialization where we just don't provide an initializer for any subobject. But the first (and only) subobject is an A
, which we're trying to initialize from {}
(during aggregate initialization, any subobject without an explicit initializer is copy-initialized from {}
), which we can't do because A
's constructor is protected and we are not a friend (see also, the quoted note).
Note that, just for fun, in C++20 the definition of aggregate will change again.
1
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class withB{A{}}
, and if such initializer is missing, an "empty initializer" is added for theA
subobject, and not one for each members ofA
, as I would have thought before.
– Holt
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
add a comment |
In C++14, the definition of aggregate was:
An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
Hence, B
is not an aggregate. As a result B{}
is surely not aggregate initialization, and B{}
and B()
end up meaning the same thing. They both just invoke B
's default constructor.
However, in C++17, the definition of aggregate was changed to:
An aggregate is an array or a class with
- no user-provided, explicit, or inherited constructors ([class.ctor]),
- no private or protected non-static data members (Clause [class.access]),
- no virtual functions, and
no virtual, private, or protected base classes ([class.mi]).
[ Note: Aggregate initialization does not allow accessing protected and private base class' members or constructors. — end note ]
The restriction is no longer on any base classes, but just on virtual/private/protected ones. But B
has a public base class. It is now an aggregate! And C++17 aggregate initialization does allow for initializing base class subobjects.
In particular, B{}
is aggregate initialization where we just don't provide an initializer for any subobject. But the first (and only) subobject is an A
, which we're trying to initialize from {}
(during aggregate initialization, any subobject without an explicit initializer is copy-initialized from {}
), which we can't do because A
's constructor is protected and we are not a friend (see also, the quoted note).
Note that, just for fun, in C++20 the definition of aggregate will change again.
1
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class withB{A{}}
, and if such initializer is missing, an "empty initializer" is added for theA
subobject, and not one for each members ofA
, as I would have thought before.
– Holt
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
add a comment |
In C++14, the definition of aggregate was:
An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
Hence, B
is not an aggregate. As a result B{}
is surely not aggregate initialization, and B{}
and B()
end up meaning the same thing. They both just invoke B
's default constructor.
However, in C++17, the definition of aggregate was changed to:
An aggregate is an array or a class with
- no user-provided, explicit, or inherited constructors ([class.ctor]),
- no private or protected non-static data members (Clause [class.access]),
- no virtual functions, and
no virtual, private, or protected base classes ([class.mi]).
[ Note: Aggregate initialization does not allow accessing protected and private base class' members or constructors. — end note ]
The restriction is no longer on any base classes, but just on virtual/private/protected ones. But B
has a public base class. It is now an aggregate! And C++17 aggregate initialization does allow for initializing base class subobjects.
In particular, B{}
is aggregate initialization where we just don't provide an initializer for any subobject. But the first (and only) subobject is an A
, which we're trying to initialize from {}
(during aggregate initialization, any subobject without an explicit initializer is copy-initialized from {}
), which we can't do because A
's constructor is protected and we are not a friend (see also, the quoted note).
Note that, just for fun, in C++20 the definition of aggregate will change again.
In C++14, the definition of aggregate was:
An aggregate is an array or a class (Clause [class]) with no user-provided constructors ([class.ctor]), no private or protected non-static data members (Clause [class.access]), no base classes (Clause [class.derived]), and no virtual functions ([class.virtual]).
Hence, B
is not an aggregate. As a result B{}
is surely not aggregate initialization, and B{}
and B()
end up meaning the same thing. They both just invoke B
's default constructor.
However, in C++17, the definition of aggregate was changed to:
An aggregate is an array or a class with
- no user-provided, explicit, or inherited constructors ([class.ctor]),
- no private or protected non-static data members (Clause [class.access]),
- no virtual functions, and
no virtual, private, or protected base classes ([class.mi]).
[ Note: Aggregate initialization does not allow accessing protected and private base class' members or constructors. — end note ]
The restriction is no longer on any base classes, but just on virtual/private/protected ones. But B
has a public base class. It is now an aggregate! And C++17 aggregate initialization does allow for initializing base class subobjects.
In particular, B{}
is aggregate initialization where we just don't provide an initializer for any subobject. But the first (and only) subobject is an A
, which we're trying to initialize from {}
(during aggregate initialization, any subobject without an explicit initializer is copy-initialized from {}
), which we can't do because A
's constructor is protected and we are not a friend (see also, the quoted note).
Note that, just for fun, in C++20 the definition of aggregate will change again.
answered 2 days ago
BarryBarry
178k18308565
178k18308565
1
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class withB{A{}}
, and if such initializer is missing, an "empty initializer" is added for theA
subobject, and not one for each members ofA
, as I would have thought before.
– Holt
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
add a comment |
1
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class withB{A{}}
, and if such initializer is missing, an "empty initializer" is added for theA
subobject, and not one for each members ofA
, as I would have thought before.
– Holt
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
1
1
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class with
B{A{}}
, and if such initializer is missing, an "empty initializer" is added for the A
subobject, and not one for each members of A
, as I would have thought before.– Holt
2 days ago
@LightnessRacesinOrbit What was actually confusing for most of us (I think) was how you (can) initialize aggregate with base class with
B{A{}}
, and if such initializer is missing, an "empty initializer" is added for the A
subobject, and not one for each members of A
, as I would have thought before.– Holt
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
@Holt Yep agreed
– Lightness Races in Orbit
2 days ago
add a comment |
From my understanding of https://en.cppreference.com/w/cpp/language/value_initialization
B{}
does an aggregate_initialization,
and since C++17:
The effects of aggregate initialization are:
- Each direct public base, (since C++17) [..] is copy-initialized from the corresponding clause of the initializer list.
and in our case:
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
So B{/*constructor of A*/}
need to construct base class A, which is protected...
add a comment |
From my understanding of https://en.cppreference.com/w/cpp/language/value_initialization
B{}
does an aggregate_initialization,
and since C++17:
The effects of aggregate initialization are:
- Each direct public base, (since C++17) [..] is copy-initialized from the corresponding clause of the initializer list.
and in our case:
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
So B{/*constructor of A*/}
need to construct base class A, which is protected...
add a comment |
From my understanding of https://en.cppreference.com/w/cpp/language/value_initialization
B{}
does an aggregate_initialization,
and since C++17:
The effects of aggregate initialization are:
- Each direct public base, (since C++17) [..] is copy-initialized from the corresponding clause of the initializer list.
and in our case:
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
So B{/*constructor of A*/}
need to construct base class A, which is protected...
From my understanding of https://en.cppreference.com/w/cpp/language/value_initialization
B{}
does an aggregate_initialization,
and since C++17:
The effects of aggregate initialization are:
- Each direct public base, (since C++17) [..] is copy-initialized from the corresponding clause of the initializer list.
and in our case:
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
So B{/*constructor of A*/}
need to construct base class A, which is protected...
answered 2 days ago
Jarod42Jarod42
114k12101182
114k12101182
add a comment |
add a comment |
The final draft of C++17 n4659 has a compatibility section which contains the changes with respect to previous versions.
C.4.4 Clause 11: declarators [diff.cpp14.decl]
11.6.1
Change: Definition of an aggregate is extended to apply to user-defined types with base classes.
Rationale: To increase
convenience of aggregate initialization.
Effect on original feature:
Valid C++ 2014 code may fail to compile or produce different results
in this International Standard; initialization from an empty
initializer list will perform aggregate initialization instead of
invoking a default constructor for the affected types:
struct derived;
struct base {
friend struct derived;
private:
base();
};
struct derived : base {};
derived d1{}; // Error. The code was well-formed before.
derived d2; // still OK
I compiled the above example code with -std=c++14
and it compiled but failed to compile with -std=c++17
.
I believe that could be the reason why the code in the OP fails with B{}
but succeeds with B()
.
add a comment |
The final draft of C++17 n4659 has a compatibility section which contains the changes with respect to previous versions.
C.4.4 Clause 11: declarators [diff.cpp14.decl]
11.6.1
Change: Definition of an aggregate is extended to apply to user-defined types with base classes.
Rationale: To increase
convenience of aggregate initialization.
Effect on original feature:
Valid C++ 2014 code may fail to compile or produce different results
in this International Standard; initialization from an empty
initializer list will perform aggregate initialization instead of
invoking a default constructor for the affected types:
struct derived;
struct base {
friend struct derived;
private:
base();
};
struct derived : base {};
derived d1{}; // Error. The code was well-formed before.
derived d2; // still OK
I compiled the above example code with -std=c++14
and it compiled but failed to compile with -std=c++17
.
I believe that could be the reason why the code in the OP fails with B{}
but succeeds with B()
.
add a comment |
The final draft of C++17 n4659 has a compatibility section which contains the changes with respect to previous versions.
C.4.4 Clause 11: declarators [diff.cpp14.decl]
11.6.1
Change: Definition of an aggregate is extended to apply to user-defined types with base classes.
Rationale: To increase
convenience of aggregate initialization.
Effect on original feature:
Valid C++ 2014 code may fail to compile or produce different results
in this International Standard; initialization from an empty
initializer list will perform aggregate initialization instead of
invoking a default constructor for the affected types:
struct derived;
struct base {
friend struct derived;
private:
base();
};
struct derived : base {};
derived d1{}; // Error. The code was well-formed before.
derived d2; // still OK
I compiled the above example code with -std=c++14
and it compiled but failed to compile with -std=c++17
.
I believe that could be the reason why the code in the OP fails with B{}
but succeeds with B()
.
The final draft of C++17 n4659 has a compatibility section which contains the changes with respect to previous versions.
C.4.4 Clause 11: declarators [diff.cpp14.decl]
11.6.1
Change: Definition of an aggregate is extended to apply to user-defined types with base classes.
Rationale: To increase
convenience of aggregate initialization.
Effect on original feature:
Valid C++ 2014 code may fail to compile or produce different results
in this International Standard; initialization from an empty
initializer list will perform aggregate initialization instead of
invoking a default constructor for the affected types:
struct derived;
struct base {
friend struct derived;
private:
base();
};
struct derived : base {};
derived d1{}; // Error. The code was well-formed before.
derived d2; // still OK
I compiled the above example code with -std=c++14
and it compiled but failed to compile with -std=c++17
.
I believe that could be the reason why the code in the OP fails with B{}
but succeeds with B()
.
edited 2 days ago
answered 2 days ago
P.WP.W
11.8k3842
11.8k3842
add a comment |
add a comment |
RyArazi is a new contributor. Be nice, and check out our Code of Conduct.
RyArazi is a new contributor. Be nice, and check out our Code of Conduct.
RyArazi is a new contributor. Be nice, and check out our Code of Conduct.
RyArazi is a new contributor. Be nice, and check out our Code of Conduct.
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%2f54092781%2fcompilation-error-when-using-empty-list-initialization-constructor-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
1
Try adding this flag:
-std=c++0x
. I am not sure though.– DimChtz
2 days ago
1
@DimChtz That changes the standard to C++11 draft, on compilers old enough to support its pre-standardisation name. Probably not helpful.
– Lightness Races in Orbit
2 days ago
What are you expecting A to be? Doesn't look valid to me. {} is an initializer or scope wrapper, () is use to wrap parameters and parentheses. In your case A() is a constructor with nothing to initialise. Your compilation error is correct, return B() returns an object with nothing in it, whilst calling the empty constructor first.
– SPlatten
2 days ago
1
@SPlatten Well, C++ isn't an OO language, so that's reasonable :)
– Lightness Races in Orbit
2 days ago
3
@SPlatten Bjarne may originally have called it "C With Classes", and implied that this makes it OO, but he was wrong. Okay, I'll be charitable and change that to say that the generally-accepted terminology has shifted in the interim, as things were added and times changed. C++ is multi-paradigm, supporting class-based OO as an option but alternatives too (imperative, concurrent, template metaprogramming). Java has elements of some of these things but is fundamentally OO in a way that C++ never was.
– Lightness Races in Orbit
2 days ago