Why does this function pointer assignment work when assigned directly but not with the conditional operator?Alternative to taking the address of a standard library function / possibly ill-formed behaviourWhy does random() work in cstdlib? (Ubuntu 10.10)Can we overload main() function in C++?How does overloaded template function selection (pattern matching) work in std::vector insert?Why does the arrow (->) operator in C exist?Can't access std::move(…) C++ 11Eclipse c++11 thread support not workingError “was not declared in this scope” in functionAmbiguous call: int to double or boolcondition in template function implementation depending on whether the type is a pointermissing template arguments before and variable or field 'printVector' declared void
Did any of the founding fathers anticipate Lysander Spooner's criticism of the constitution?
Why do players in the past play much longer tournaments than today's top players?
<schwitz>, <zwinker> etc. Does German always use 2nd Person Singular Imperative verbs for emoticons? If so, why?
What's the point of this scene involving Flash Thompson at the airport?
Is killing off one of my queer characters homophobic?
What could be some effects of (physical) Mana consumption that prevent long term abuse?
Who Can Help Retag This?
How do I determine whether a permit is required for a new gas line?
Correct use of ergeben?
QGIS Welcome page: What is 'pin to list' for?
Dropping outliers based on "2.5 times the RMSE"
Shortest distance around a pyramid
Is purchasing foreign currency before going abroad a losing proposition?
Filtering fine silt/mud from water (not necessarily bacteria etc.)
Supporting developers who insist on using their pet language
Are there any double stars that I can actually see orbit each other?
Are there any intersection of Theory A and Theory B?
Redirect https to fqdn
When did the Roman Empire fall according to contemporaries?
Can I intentionally omit previous work experience or pretend it doesn't exist when applying for jobs?
Is Trump personally blocking people on Twitter?
Robbers: The Hidden OEIS Substring
If a specific mass of air is polluted, will the pollution stick with it?
Why does Hellboy file down his horns?
Why does this function pointer assignment work when assigned directly but not with the conditional operator?
Alternative to taking the address of a standard library function / possibly ill-formed behaviourWhy does random() work in cstdlib? (Ubuntu 10.10)Can we overload main() function in C++?How does overloaded template function selection (pattern matching) work in std::vector insert?Why does the arrow (->) operator in C exist?Can't access std::move(…) C++ 11Eclipse c++11 thread support not workingError “was not declared in this scope” in functionAmbiguous call: int to double or boolcondition in template function implementation depending on whether the type is a pointermissing template arguments before and variable or field 'printVector' declared void
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
(No #include's were used for this example, compiled on MacOS10.14, Eclipse IDE, with g++, options -O0 -g3 -Wall -c -fmessage-length=0)
Assuming this variable declaration:
int (*fun)(int);
This fails to compile with "invalid overload of std::toupper and std::tolower".
fun = (1 ? std::toupper : std::tolower); // ERROR, invalid overload
And this compiles OK:
if (1)
fun = std::toupper; // OK
else
fun = std::tolower; // OK
c++ function pointers overloading
add a comment |
(No #include's were used for this example, compiled on MacOS10.14, Eclipse IDE, with g++, options -O0 -g3 -Wall -c -fmessage-length=0)
Assuming this variable declaration:
int (*fun)(int);
This fails to compile with "invalid overload of std::toupper and std::tolower".
fun = (1 ? std::toupper : std::tolower); // ERROR, invalid overload
And this compiles OK:
if (1)
fun = std::toupper; // OK
else
fun = std::tolower; // OK
c++ function pointers overloading
1
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Jul 4 at 12:56
add a comment |
(No #include's were used for this example, compiled on MacOS10.14, Eclipse IDE, with g++, options -O0 -g3 -Wall -c -fmessage-length=0)
Assuming this variable declaration:
int (*fun)(int);
This fails to compile with "invalid overload of std::toupper and std::tolower".
fun = (1 ? std::toupper : std::tolower); // ERROR, invalid overload
And this compiles OK:
if (1)
fun = std::toupper; // OK
else
fun = std::tolower; // OK
c++ function pointers overloading
(No #include's were used for this example, compiled on MacOS10.14, Eclipse IDE, with g++, options -O0 -g3 -Wall -c -fmessage-length=0)
Assuming this variable declaration:
int (*fun)(int);
This fails to compile with "invalid overload of std::toupper and std::tolower".
fun = (1 ? std::toupper : std::tolower); // ERROR, invalid overload
And this compiles OK:
if (1)
fun = std::toupper; // OK
else
fun = std::tolower; // OK
c++ function pointers overloading
c++ function pointers overloading
edited Jul 4 at 12:40
Boann
38.4k13 gold badges92 silver badges123 bronze badges
38.4k13 gold badges92 silver badges123 bronze badges
asked Jul 4 at 8:56
ph hph h
1626 bronze badges
1626 bronze badges
1
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Jul 4 at 12:56
add a comment |
1
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Jul 4 at 12:56
1
1
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Jul 4 at 12:56
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Jul 4 at 12:56
add a comment |
3 Answers
3
active
oldest
votes
std::toupper
(1 and 2) and std::tolower
(1 and 2) are overloaded. When determining the common type between them for the conditional operator (before the assignment to chr2fun
), which overloading should be used can't be determined.
You can use static_cast
to specify which one should be considered. (Presicely, to force the overload resolution happens at first respectively, then the trouble in determining the common type disappears.)
static_cast
may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
e.g.
chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper)
: static_cast<int(*)(int)>(std::tolower));
For the 2nd case, chr2fun
is assigned directly; the type of chr2fun
is explicit and the correct overloading would be selected in overload resolution.
(emphasis mine)
In all these contexts, the function selected from the overload set is the function whose type matches the pointer to function, reference to function, or pointer to member function type that is expected by target: the object or reference being initialized, the left-hand side of the assignment, function or operator parameter, the return type of a function, the target type of a cast, or the type of the template parameter, respectively.
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
1
@MichaelChourdakis it's unspecified whether that works, if#include <cctype>
was used (the implementation must place the names instd
but can optionally also place them in global namespace)
– M.M
Jul 4 at 9:10
1
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
1
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
2
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
|
show 2 more comments
In the first case, the compiler balks before even getting to the assignment. A simplified expression:
(true ? std::toupper : std::tolower)
Will fail to compile if there are multiple overloads of toupper
/tolower
present. This is because the ternary operator's return type must be established based solely on the types of 2nd and 3rd argument, without ever looking at the context where the result of it is used.
Funny enough, even if one of those arguments isn't an overloaded function, that's still not enough. Reasons for that are less obvious, and have more to do with overload resolution1 rules and where they apply. A cast is precisely one of seven possibilities to trigger it, and determining the target type of ternary operators itself isn't.
In the case of direct assignment, the rhs of assignment must fit the lhs, and so there's no ambiguity.
Either way, as pointed out by @Caleth, according to 16.5.4.2.1.6, this code has unspecified behaviour.
1The C++ Reference has an incorrect C++ Standard paragraph. [over.over] is actually 12.4.
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
2
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of?:
?
– Bartek Banachewicz
Jul 4 at 9:17
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
add a comment |
This snippet compiles fine with gcc 9.1
#include <cctype>
int chr2fun(bool str2modus)
const bool STR2UP = true;
int (*chr2fun)(int);
if (str2modus == STR2UP)
chr2fun = std::toupper;
else
chr2fun = std::tolower;
chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
On what platform and with which compiler do you get the error?
2
I suspect it will turn out they have<locale>
included which introduces extra overloads forstd::toupper
etc.
– M.M
Jul 4 at 9:06
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%2f56884194%2fwhy-does-this-function-pointer-assignment-work-when-assigned-directly-but-not-wi%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
std::toupper
(1 and 2) and std::tolower
(1 and 2) are overloaded. When determining the common type between them for the conditional operator (before the assignment to chr2fun
), which overloading should be used can't be determined.
You can use static_cast
to specify which one should be considered. (Presicely, to force the overload resolution happens at first respectively, then the trouble in determining the common type disappears.)
static_cast
may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
e.g.
chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper)
: static_cast<int(*)(int)>(std::tolower));
For the 2nd case, chr2fun
is assigned directly; the type of chr2fun
is explicit and the correct overloading would be selected in overload resolution.
(emphasis mine)
In all these contexts, the function selected from the overload set is the function whose type matches the pointer to function, reference to function, or pointer to member function type that is expected by target: the object or reference being initialized, the left-hand side of the assignment, function or operator parameter, the return type of a function, the target type of a cast, or the type of the template parameter, respectively.
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
1
@MichaelChourdakis it's unspecified whether that works, if#include <cctype>
was used (the implementation must place the names instd
but can optionally also place them in global namespace)
– M.M
Jul 4 at 9:10
1
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
1
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
2
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
|
show 2 more comments
std::toupper
(1 and 2) and std::tolower
(1 and 2) are overloaded. When determining the common type between them for the conditional operator (before the assignment to chr2fun
), which overloading should be used can't be determined.
You can use static_cast
to specify which one should be considered. (Presicely, to force the overload resolution happens at first respectively, then the trouble in determining the common type disappears.)
static_cast
may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
e.g.
chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper)
: static_cast<int(*)(int)>(std::tolower));
For the 2nd case, chr2fun
is assigned directly; the type of chr2fun
is explicit and the correct overloading would be selected in overload resolution.
(emphasis mine)
In all these contexts, the function selected from the overload set is the function whose type matches the pointer to function, reference to function, or pointer to member function type that is expected by target: the object or reference being initialized, the left-hand side of the assignment, function or operator parameter, the return type of a function, the target type of a cast, or the type of the template parameter, respectively.
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
1
@MichaelChourdakis it's unspecified whether that works, if#include <cctype>
was used (the implementation must place the names instd
but can optionally also place them in global namespace)
– M.M
Jul 4 at 9:10
1
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
1
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
2
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
|
show 2 more comments
std::toupper
(1 and 2) and std::tolower
(1 and 2) are overloaded. When determining the common type between them for the conditional operator (before the assignment to chr2fun
), which overloading should be used can't be determined.
You can use static_cast
to specify which one should be considered. (Presicely, to force the overload resolution happens at first respectively, then the trouble in determining the common type disappears.)
static_cast
may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
e.g.
chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper)
: static_cast<int(*)(int)>(std::tolower));
For the 2nd case, chr2fun
is assigned directly; the type of chr2fun
is explicit and the correct overloading would be selected in overload resolution.
(emphasis mine)
In all these contexts, the function selected from the overload set is the function whose type matches the pointer to function, reference to function, or pointer to member function type that is expected by target: the object or reference being initialized, the left-hand side of the assignment, function or operator parameter, the return type of a function, the target type of a cast, or the type of the template parameter, respectively.
std::toupper
(1 and 2) and std::tolower
(1 and 2) are overloaded. When determining the common type between them for the conditional operator (before the assignment to chr2fun
), which overloading should be used can't be determined.
You can use static_cast
to specify which one should be considered. (Presicely, to force the overload resolution happens at first respectively, then the trouble in determining the common type disappears.)
static_cast
may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
e.g.
chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper)
: static_cast<int(*)(int)>(std::tolower));
For the 2nd case, chr2fun
is assigned directly; the type of chr2fun
is explicit and the correct overloading would be selected in overload resolution.
(emphasis mine)
In all these contexts, the function selected from the overload set is the function whose type matches the pointer to function, reference to function, or pointer to member function type that is expected by target: the object or reference being initialized, the left-hand side of the assignment, function or operator parameter, the return type of a function, the target type of a cast, or the type of the template parameter, respectively.
edited Jul 4 at 10:22
answered Jul 4 at 9:02
songyuanyaosongyuanyao
100k11 gold badges199 silver badges263 bronze badges
100k11 gold badges199 silver badges263 bronze badges
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
1
@MichaelChourdakis it's unspecified whether that works, if#include <cctype>
was used (the implementation must place the names instd
but can optionally also place them in global namespace)
– M.M
Jul 4 at 9:10
1
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
1
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
2
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
|
show 2 more comments
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
1
@MichaelChourdakis it's unspecified whether that works, if#include <cctype>
was used (the implementation must place the names instd
but can optionally also place them in global namespace)
– M.M
Jul 4 at 9:10
1
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
1
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
2
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
Adding to the answer, using them without std:: works.
– Michael Chourdakis
Jul 4 at 9:05
1
1
@MichaelChourdakis it's unspecified whether that works, if
#include <cctype>
was used (the implementation must place the names in std
but can optionally also place them in global namespace)– M.M
Jul 4 at 9:10
@MichaelChourdakis it's unspecified whether that works, if
#include <cctype>
was used (the implementation must place the names in std
but can optionally also place them in global namespace)– M.M
Jul 4 at 9:10
1
1
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
@MartinBonner I tried, but both are required. wandbox.org/permlink/NLB23HjYBiReU7Tx
– songyuanyao
Jul 4 at 9:21
1
1
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
@BartekBanachewicz It's not easy to answer... I think it's just the standard doesn't require the compiler to do this; it might require more complex analyses.
– songyuanyao
Jul 4 at 9:28
2
2
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
@BartekBanachewicz Usually the reason for "optionally place in global namespace" is because different real implementations do things differently, and putting a requirement to either mandate or forbid this would put undue implementation effort on some implementations. (I have a bit set that C++98 tried to insist on "std:: only" with some headers, and nearly all implementations went ahead and ignored them because it was too hard to integrate with existing C libraries like that.)
– Martin Bonner
Jul 4 at 9:37
|
show 2 more comments
In the first case, the compiler balks before even getting to the assignment. A simplified expression:
(true ? std::toupper : std::tolower)
Will fail to compile if there are multiple overloads of toupper
/tolower
present. This is because the ternary operator's return type must be established based solely on the types of 2nd and 3rd argument, without ever looking at the context where the result of it is used.
Funny enough, even if one of those arguments isn't an overloaded function, that's still not enough. Reasons for that are less obvious, and have more to do with overload resolution1 rules and where they apply. A cast is precisely one of seven possibilities to trigger it, and determining the target type of ternary operators itself isn't.
In the case of direct assignment, the rhs of assignment must fit the lhs, and so there's no ambiguity.
Either way, as pointed out by @Caleth, according to 16.5.4.2.1.6, this code has unspecified behaviour.
1The C++ Reference has an incorrect C++ Standard paragraph. [over.over] is actually 12.4.
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
2
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of?:
?
– Bartek Banachewicz
Jul 4 at 9:17
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
add a comment |
In the first case, the compiler balks before even getting to the assignment. A simplified expression:
(true ? std::toupper : std::tolower)
Will fail to compile if there are multiple overloads of toupper
/tolower
present. This is because the ternary operator's return type must be established based solely on the types of 2nd and 3rd argument, without ever looking at the context where the result of it is used.
Funny enough, even if one of those arguments isn't an overloaded function, that's still not enough. Reasons for that are less obvious, and have more to do with overload resolution1 rules and where they apply. A cast is precisely one of seven possibilities to trigger it, and determining the target type of ternary operators itself isn't.
In the case of direct assignment, the rhs of assignment must fit the lhs, and so there's no ambiguity.
Either way, as pointed out by @Caleth, according to 16.5.4.2.1.6, this code has unspecified behaviour.
1The C++ Reference has an incorrect C++ Standard paragraph. [over.over] is actually 12.4.
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
2
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of?:
?
– Bartek Banachewicz
Jul 4 at 9:17
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
add a comment |
In the first case, the compiler balks before even getting to the assignment. A simplified expression:
(true ? std::toupper : std::tolower)
Will fail to compile if there are multiple overloads of toupper
/tolower
present. This is because the ternary operator's return type must be established based solely on the types of 2nd and 3rd argument, without ever looking at the context where the result of it is used.
Funny enough, even if one of those arguments isn't an overloaded function, that's still not enough. Reasons for that are less obvious, and have more to do with overload resolution1 rules and where they apply. A cast is precisely one of seven possibilities to trigger it, and determining the target type of ternary operators itself isn't.
In the case of direct assignment, the rhs of assignment must fit the lhs, and so there's no ambiguity.
Either way, as pointed out by @Caleth, according to 16.5.4.2.1.6, this code has unspecified behaviour.
1The C++ Reference has an incorrect C++ Standard paragraph. [over.over] is actually 12.4.
In the first case, the compiler balks before even getting to the assignment. A simplified expression:
(true ? std::toupper : std::tolower)
Will fail to compile if there are multiple overloads of toupper
/tolower
present. This is because the ternary operator's return type must be established based solely on the types of 2nd and 3rd argument, without ever looking at the context where the result of it is used.
Funny enough, even if one of those arguments isn't an overloaded function, that's still not enough. Reasons for that are less obvious, and have more to do with overload resolution1 rules and where they apply. A cast is precisely one of seven possibilities to trigger it, and determining the target type of ternary operators itself isn't.
In the case of direct assignment, the rhs of assignment must fit the lhs, and so there's no ambiguity.
Either way, as pointed out by @Caleth, according to 16.5.4.2.1.6, this code has unspecified behaviour.
1The C++ Reference has an incorrect C++ Standard paragraph. [over.over] is actually 12.4.
edited Jul 4 at 9:36
answered Jul 4 at 9:11
Bartek BanachewiczBartek Banachewicz
31.2k5 gold badges70 silver badges113 bronze badges
31.2k5 gold badges70 silver badges113 bronze badges
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
2
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of?:
?
– Bartek Banachewicz
Jul 4 at 9:17
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
add a comment |
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
2
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of?:
?
– Bartek Banachewicz
Jul 4 at 9:17
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
thx, thats real useful info, but int this case, toupper and tolower have identical signatures...?
– ph h
Jul 4 at 9:16
2
2
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of
?:
?– Bartek Banachewicz
Jul 4 at 9:17
@phh They have identical sets of signatures because of their overloads. Which matching pair should be used to determine the final type of
?:
?– Bartek Banachewicz
Jul 4 at 9:17
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
omg, am i a beginner! thx a lot, that answered my question!! :-)
– ph h
Jul 4 at 9:18
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
Caleth's reference is from the draft C++2a. What before that?
– Deduplicator
Jul 4 at 21:32
add a comment |
This snippet compiles fine with gcc 9.1
#include <cctype>
int chr2fun(bool str2modus)
const bool STR2UP = true;
int (*chr2fun)(int);
if (str2modus == STR2UP)
chr2fun = std::toupper;
else
chr2fun = std::tolower;
chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
On what platform and with which compiler do you get the error?
2
I suspect it will turn out they have<locale>
included which introduces extra overloads forstd::toupper
etc.
– M.M
Jul 4 at 9:06
add a comment |
This snippet compiles fine with gcc 9.1
#include <cctype>
int chr2fun(bool str2modus)
const bool STR2UP = true;
int (*chr2fun)(int);
if (str2modus == STR2UP)
chr2fun = std::toupper;
else
chr2fun = std::tolower;
chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
On what platform and with which compiler do you get the error?
2
I suspect it will turn out they have<locale>
included which introduces extra overloads forstd::toupper
etc.
– M.M
Jul 4 at 9:06
add a comment |
This snippet compiles fine with gcc 9.1
#include <cctype>
int chr2fun(bool str2modus)
const bool STR2UP = true;
int (*chr2fun)(int);
if (str2modus == STR2UP)
chr2fun = std::toupper;
else
chr2fun = std::tolower;
chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
On what platform and with which compiler do you get the error?
This snippet compiles fine with gcc 9.1
#include <cctype>
int chr2fun(bool str2modus)
const bool STR2UP = true;
int (*chr2fun)(int);
if (str2modus == STR2UP)
chr2fun = std::toupper;
else
chr2fun = std::tolower;
chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
On what platform and with which compiler do you get the error?
answered Jul 4 at 9:05
schorsch312schorsch312
2,8492 gold badges14 silver badges35 bronze badges
2,8492 gold badges14 silver badges35 bronze badges
2
I suspect it will turn out they have<locale>
included which introduces extra overloads forstd::toupper
etc.
– M.M
Jul 4 at 9:06
add a comment |
2
I suspect it will turn out they have<locale>
included which introduces extra overloads forstd::toupper
etc.
– M.M
Jul 4 at 9:06
2
2
I suspect it will turn out they have
<locale>
included which introduces extra overloads for std::toupper
etc.– M.M
Jul 4 at 9:06
I suspect it will turn out they have
<locale>
included which introduces extra overloads for std::toupper
etc.– M.M
Jul 4 at 9:06
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%2f56884194%2fwhy-does-this-function-pointer-assignment-work-when-assigned-directly-but-not-wi%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
Comments are not for extended discussion; this conversation has been moved to chat.
– Samuel Liew♦
Jul 4 at 12:56