User-defined conversions sequence
Before I studied the explicit
keyword, my teacher said: "compiler doesn't execute consecutive user defined conversion". If it is true, are there any errors in my code? Or have I misunderstood my teacher? I'm working in VS2017.
#include<iostream>
#include <string>
class Myclass {
public:
Myclass() {
std::cout << "Myclass" << std::endl;
}
};
class Myclass1 {
public:
Myclass1(Myclass m) {
std::cout << "Myclass1" << std::endl;
}
};
class Myclass2{
public:
Myclass2(Myclass1 m) {
std::cout << "Myclass2" << std::endl;
}
};
int main() {
Myclass2 m2 = Myclass{};
}
c++ type-conversion implicit-conversion
add a comment |
Before I studied the explicit
keyword, my teacher said: "compiler doesn't execute consecutive user defined conversion". If it is true, are there any errors in my code? Or have I misunderstood my teacher? I'm working in VS2017.
#include<iostream>
#include <string>
class Myclass {
public:
Myclass() {
std::cout << "Myclass" << std::endl;
}
};
class Myclass1 {
public:
Myclass1(Myclass m) {
std::cout << "Myclass1" << std::endl;
}
};
class Myclass2{
public:
Myclass2(Myclass1 m) {
std::cout << "Myclass2" << std::endl;
}
};
int main() {
Myclass2 m2 = Myclass{};
}
c++ type-conversion implicit-conversion
add a comment |
Before I studied the explicit
keyword, my teacher said: "compiler doesn't execute consecutive user defined conversion". If it is true, are there any errors in my code? Or have I misunderstood my teacher? I'm working in VS2017.
#include<iostream>
#include <string>
class Myclass {
public:
Myclass() {
std::cout << "Myclass" << std::endl;
}
};
class Myclass1 {
public:
Myclass1(Myclass m) {
std::cout << "Myclass1" << std::endl;
}
};
class Myclass2{
public:
Myclass2(Myclass1 m) {
std::cout << "Myclass2" << std::endl;
}
};
int main() {
Myclass2 m2 = Myclass{};
}
c++ type-conversion implicit-conversion
Before I studied the explicit
keyword, my teacher said: "compiler doesn't execute consecutive user defined conversion". If it is true, are there any errors in my code? Or have I misunderstood my teacher? I'm working in VS2017.
#include<iostream>
#include <string>
class Myclass {
public:
Myclass() {
std::cout << "Myclass" << std::endl;
}
};
class Myclass1 {
public:
Myclass1(Myclass m) {
std::cout << "Myclass1" << std::endl;
}
};
class Myclass2{
public:
Myclass2(Myclass1 m) {
std::cout << "Myclass2" << std::endl;
}
};
int main() {
Myclass2 m2 = Myclass{};
}
c++ type-conversion implicit-conversion
c++ type-conversion implicit-conversion
edited Nov 14 '18 at 10:51
Evg
3,81221334
3,81221334
asked Nov 14 '18 at 9:16
User8500049User8500049
1114
1114
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
compiler doesn't execute consecutive user defined conversion
Your teacher is right. In your code sample it means Myclass
cannot be converted to Myclass1
when you assign in:
Myclass2 m2 = Myclass{};
Because constructor expects Myclass1
when creating Myclass2
, and compiler cannot consecutively convert Myclass
to Myclass1
and then use it for creating Myclass2
. But if you have following line:
Myclass1 m2 = Myclass{};
It will work, because constructor of Myclass1
takes Myclass
as argument.
Update:
You may ask why this works:
Myclass2 m2 {Myclass{}};
Because in this case, constructor is called and conversion can be done implicitly unless you declare Myclass1
as explicit
which will fail code compilation (Thanks Fureeish for reminder), but in:
Myclass2 m2 = Myclass{};
is like calling copy-constructor which needs reference. so if you write it like this, it will work:
Myclass2 m2 = Myclass1(Myclass{});
As EVG mentioned, Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-) is not activated.
2
Worth noting that OP mentionedexplicit
. In your first example in your edit, there is a temporaryMyclass1
object created implicitely fromMyclass
instance (that's why there is aMyclass2
constructor invoked, which requiresMyclass1
object). If you makeMyclass1
's constructorexplicit
, it will fail
– Fureeish
Nov 14 '18 at 9:30
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.
– Evg
Nov 14 '18 at 9:46
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
add a comment |
The line
Myclass2 m2 = Myclass{};
means copy-initialization. Citing cppreference.com:
If
T
is a class type, and the cv-unqualified version of the type ofother
is notT
or derived fromT
[...], user-defined conversion sequences that can convert from the type ofother
toT
[...] are examined and the best one is selected through overload resolution.
Citing further:
A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call.
So, Myclass2 m2 = Myclass{};
is not acceptable because it would involve two user-defined conversions.
Now let's take a look at
Myclass2 m2 {Myclass{}};
suggested in Afshin's answer. This is a direct-initialization. The rules are different:
The constructors of
T
are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
The constructor of Myclass2
accepts Myclass1
, and you need one user-defined conversion to get Myclass1
from Myclass
. Hence, it compiles.
Note that in VS copy-initilization is treated like direct-initilization if conformance mode (/premissive-
) is not activated (by default). So, VS accepts Myclass2 m2 = Myclass{};
treating it as direct-initilization. See this document for examples.
add a comment |
The other answers are burying the lede: The code you’ve written is indeed invalid. MSVC accepts it by default, but MSVC is wrong to do so. You can force MSVC to be stricter by using the command line switch /permissive-
. (You should use that switch.)
Other compilers (GCC, clang), reject it.
All compilers accept the code once you change the copy initialisation to direct initialisation as shown in the other answers.
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
});
}
});
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%2f53296622%2fuser-defined-conversions-sequence%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
compiler doesn't execute consecutive user defined conversion
Your teacher is right. In your code sample it means Myclass
cannot be converted to Myclass1
when you assign in:
Myclass2 m2 = Myclass{};
Because constructor expects Myclass1
when creating Myclass2
, and compiler cannot consecutively convert Myclass
to Myclass1
and then use it for creating Myclass2
. But if you have following line:
Myclass1 m2 = Myclass{};
It will work, because constructor of Myclass1
takes Myclass
as argument.
Update:
You may ask why this works:
Myclass2 m2 {Myclass{}};
Because in this case, constructor is called and conversion can be done implicitly unless you declare Myclass1
as explicit
which will fail code compilation (Thanks Fureeish for reminder), but in:
Myclass2 m2 = Myclass{};
is like calling copy-constructor which needs reference. so if you write it like this, it will work:
Myclass2 m2 = Myclass1(Myclass{});
As EVG mentioned, Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-) is not activated.
2
Worth noting that OP mentionedexplicit
. In your first example in your edit, there is a temporaryMyclass1
object created implicitely fromMyclass
instance (that's why there is aMyclass2
constructor invoked, which requiresMyclass1
object). If you makeMyclass1
's constructorexplicit
, it will fail
– Fureeish
Nov 14 '18 at 9:30
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.
– Evg
Nov 14 '18 at 9:46
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
add a comment |
compiler doesn't execute consecutive user defined conversion
Your teacher is right. In your code sample it means Myclass
cannot be converted to Myclass1
when you assign in:
Myclass2 m2 = Myclass{};
Because constructor expects Myclass1
when creating Myclass2
, and compiler cannot consecutively convert Myclass
to Myclass1
and then use it for creating Myclass2
. But if you have following line:
Myclass1 m2 = Myclass{};
It will work, because constructor of Myclass1
takes Myclass
as argument.
Update:
You may ask why this works:
Myclass2 m2 {Myclass{}};
Because in this case, constructor is called and conversion can be done implicitly unless you declare Myclass1
as explicit
which will fail code compilation (Thanks Fureeish for reminder), but in:
Myclass2 m2 = Myclass{};
is like calling copy-constructor which needs reference. so if you write it like this, it will work:
Myclass2 m2 = Myclass1(Myclass{});
As EVG mentioned, Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-) is not activated.
2
Worth noting that OP mentionedexplicit
. In your first example in your edit, there is a temporaryMyclass1
object created implicitely fromMyclass
instance (that's why there is aMyclass2
constructor invoked, which requiresMyclass1
object). If you makeMyclass1
's constructorexplicit
, it will fail
– Fureeish
Nov 14 '18 at 9:30
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.
– Evg
Nov 14 '18 at 9:46
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
add a comment |
compiler doesn't execute consecutive user defined conversion
Your teacher is right. In your code sample it means Myclass
cannot be converted to Myclass1
when you assign in:
Myclass2 m2 = Myclass{};
Because constructor expects Myclass1
when creating Myclass2
, and compiler cannot consecutively convert Myclass
to Myclass1
and then use it for creating Myclass2
. But if you have following line:
Myclass1 m2 = Myclass{};
It will work, because constructor of Myclass1
takes Myclass
as argument.
Update:
You may ask why this works:
Myclass2 m2 {Myclass{}};
Because in this case, constructor is called and conversion can be done implicitly unless you declare Myclass1
as explicit
which will fail code compilation (Thanks Fureeish for reminder), but in:
Myclass2 m2 = Myclass{};
is like calling copy-constructor which needs reference. so if you write it like this, it will work:
Myclass2 m2 = Myclass1(Myclass{});
As EVG mentioned, Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-) is not activated.
compiler doesn't execute consecutive user defined conversion
Your teacher is right. In your code sample it means Myclass
cannot be converted to Myclass1
when you assign in:
Myclass2 m2 = Myclass{};
Because constructor expects Myclass1
when creating Myclass2
, and compiler cannot consecutively convert Myclass
to Myclass1
and then use it for creating Myclass2
. But if you have following line:
Myclass1 m2 = Myclass{};
It will work, because constructor of Myclass1
takes Myclass
as argument.
Update:
You may ask why this works:
Myclass2 m2 {Myclass{}};
Because in this case, constructor is called and conversion can be done implicitly unless you declare Myclass1
as explicit
which will fail code compilation (Thanks Fureeish for reminder), but in:
Myclass2 m2 = Myclass{};
is like calling copy-constructor which needs reference. so if you write it like this, it will work:
Myclass2 m2 = Myclass1(Myclass{});
As EVG mentioned, Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-) is not activated.
edited Nov 14 '18 at 9:56
answered Nov 14 '18 at 9:21
AfshinAfshin
3,0161625
3,0161625
2
Worth noting that OP mentionedexplicit
. In your first example in your edit, there is a temporaryMyclass1
object created implicitely fromMyclass
instance (that's why there is aMyclass2
constructor invoked, which requiresMyclass1
object). If you makeMyclass1
's constructorexplicit
, it will fail
– Fureeish
Nov 14 '18 at 9:30
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.
– Evg
Nov 14 '18 at 9:46
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
add a comment |
2
Worth noting that OP mentionedexplicit
. In your first example in your edit, there is a temporaryMyclass1
object created implicitely fromMyclass
instance (that's why there is aMyclass2
constructor invoked, which requiresMyclass1
object). If you makeMyclass1
's constructorexplicit
, it will fail
– Fureeish
Nov 14 '18 at 9:30
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.
– Evg
Nov 14 '18 at 9:46
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
2
2
Worth noting that OP mentioned
explicit
. In your first example in your edit, there is a temporary Myclass1
object created implicitely from Myclass
instance (that's why there is a Myclass2
constructor invoked, which requires Myclass1
object). If you make Myclass1
's constructor explicit
, it will fail– Fureeish
Nov 14 '18 at 9:30
Worth noting that OP mentioned
explicit
. In your first example in your edit, there is a temporary Myclass1
object created implicitely from Myclass
instance (that's why there is a Myclass2
constructor invoked, which requires Myclass1
object). If you make Myclass1
's constructor explicit
, it will fail– Fureeish
Nov 14 '18 at 9:30
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
@Fureeish I will add your comment.
– Afshin
Nov 14 '18 at 9:32
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.– Evg
Nov 14 '18 at 9:46
Myclass2 m2 = Myclass{};
is accepted by VS 2017 if the conformance mode (/permissive-
) is not activated.– Evg
Nov 14 '18 at 9:46
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
@Evg I didn't know that. I will add it too.
– Afshin
Nov 14 '18 at 9:52
add a comment |
The line
Myclass2 m2 = Myclass{};
means copy-initialization. Citing cppreference.com:
If
T
is a class type, and the cv-unqualified version of the type ofother
is notT
or derived fromT
[...], user-defined conversion sequences that can convert from the type ofother
toT
[...] are examined and the best one is selected through overload resolution.
Citing further:
A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call.
So, Myclass2 m2 = Myclass{};
is not acceptable because it would involve two user-defined conversions.
Now let's take a look at
Myclass2 m2 {Myclass{}};
suggested in Afshin's answer. This is a direct-initialization. The rules are different:
The constructors of
T
are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
The constructor of Myclass2
accepts Myclass1
, and you need one user-defined conversion to get Myclass1
from Myclass
. Hence, it compiles.
Note that in VS copy-initilization is treated like direct-initilization if conformance mode (/premissive-
) is not activated (by default). So, VS accepts Myclass2 m2 = Myclass{};
treating it as direct-initilization. See this document for examples.
add a comment |
The line
Myclass2 m2 = Myclass{};
means copy-initialization. Citing cppreference.com:
If
T
is a class type, and the cv-unqualified version of the type ofother
is notT
or derived fromT
[...], user-defined conversion sequences that can convert from the type ofother
toT
[...] are examined and the best one is selected through overload resolution.
Citing further:
A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call.
So, Myclass2 m2 = Myclass{};
is not acceptable because it would involve two user-defined conversions.
Now let's take a look at
Myclass2 m2 {Myclass{}};
suggested in Afshin's answer. This is a direct-initialization. The rules are different:
The constructors of
T
are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
The constructor of Myclass2
accepts Myclass1
, and you need one user-defined conversion to get Myclass1
from Myclass
. Hence, it compiles.
Note that in VS copy-initilization is treated like direct-initilization if conformance mode (/premissive-
) is not activated (by default). So, VS accepts Myclass2 m2 = Myclass{};
treating it as direct-initilization. See this document for examples.
add a comment |
The line
Myclass2 m2 = Myclass{};
means copy-initialization. Citing cppreference.com:
If
T
is a class type, and the cv-unqualified version of the type ofother
is notT
or derived fromT
[...], user-defined conversion sequences that can convert from the type ofother
toT
[...] are examined and the best one is selected through overload resolution.
Citing further:
A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call.
So, Myclass2 m2 = Myclass{};
is not acceptable because it would involve two user-defined conversions.
Now let's take a look at
Myclass2 m2 {Myclass{}};
suggested in Afshin's answer. This is a direct-initialization. The rules are different:
The constructors of
T
are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
The constructor of Myclass2
accepts Myclass1
, and you need one user-defined conversion to get Myclass1
from Myclass
. Hence, it compiles.
Note that in VS copy-initilization is treated like direct-initilization if conformance mode (/premissive-
) is not activated (by default). So, VS accepts Myclass2 m2 = Myclass{};
treating it as direct-initilization. See this document for examples.
The line
Myclass2 m2 = Myclass{};
means copy-initialization. Citing cppreference.com:
If
T
is a class type, and the cv-unqualified version of the type ofother
is notT
or derived fromT
[...], user-defined conversion sequences that can convert from the type ofother
toT
[...] are examined and the best one is selected through overload resolution.
Citing further:
A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call.
So, Myclass2 m2 = Myclass{};
is not acceptable because it would involve two user-defined conversions.
Now let's take a look at
Myclass2 m2 {Myclass{}};
suggested in Afshin's answer. This is a direct-initialization. The rules are different:
The constructors of
T
are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
The constructor of Myclass2
accepts Myclass1
, and you need one user-defined conversion to get Myclass1
from Myclass
. Hence, it compiles.
Note that in VS copy-initilization is treated like direct-initilization if conformance mode (/premissive-
) is not activated (by default). So, VS accepts Myclass2 m2 = Myclass{};
treating it as direct-initilization. See this document for examples.
edited Nov 14 '18 at 10:19
answered Nov 14 '18 at 9:35
EvgEvg
3,81221334
3,81221334
add a comment |
add a comment |
The other answers are burying the lede: The code you’ve written is indeed invalid. MSVC accepts it by default, but MSVC is wrong to do so. You can force MSVC to be stricter by using the command line switch /permissive-
. (You should use that switch.)
Other compilers (GCC, clang), reject it.
All compilers accept the code once you change the copy initialisation to direct initialisation as shown in the other answers.
add a comment |
The other answers are burying the lede: The code you’ve written is indeed invalid. MSVC accepts it by default, but MSVC is wrong to do so. You can force MSVC to be stricter by using the command line switch /permissive-
. (You should use that switch.)
Other compilers (GCC, clang), reject it.
All compilers accept the code once you change the copy initialisation to direct initialisation as shown in the other answers.
add a comment |
The other answers are burying the lede: The code you’ve written is indeed invalid. MSVC accepts it by default, but MSVC is wrong to do so. You can force MSVC to be stricter by using the command line switch /permissive-
. (You should use that switch.)
Other compilers (GCC, clang), reject it.
All compilers accept the code once you change the copy initialisation to direct initialisation as shown in the other answers.
The other answers are burying the lede: The code you’ve written is indeed invalid. MSVC accepts it by default, but MSVC is wrong to do so. You can force MSVC to be stricter by using the command line switch /permissive-
. (You should use that switch.)
Other compilers (GCC, clang), reject it.
All compilers accept the code once you change the copy initialisation to direct initialisation as shown in the other answers.
answered Nov 14 '18 at 11:58
Konrad RudolphKonrad Rudolph
395k1017821025
395k1017821025
add a comment |
add a comment |
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%2f53296622%2fuser-defined-conversions-sequence%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