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;








24















(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










share|improve this question



















  • 1





    Comments are not for extended discussion; this conversation has been moved to chat.

    – Samuel Liew
    Jul 4 at 12:56

















24















(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










share|improve this question



















  • 1





    Comments are not for extended discussion; this conversation has been moved to chat.

    – Samuel Liew
    Jul 4 at 12:56













24












24








24


4






(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










share|improve this question
















(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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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












  • 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












3 Answers
3






active

oldest

votes


















27














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.







share|improve this answer

























  • 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 in std 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


















11














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.






share|improve this answer

























  • 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


















0














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?






share|improve this answer


















  • 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














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



);













draft saved

draft discarded


















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









27














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.







share|improve this answer

























  • 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 in std 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















27














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.







share|improve this answer

























  • 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 in std 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













27












27








27







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.







share|improve this answer















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.








share|improve this answer














share|improve this answer



share|improve this answer








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 in std 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






  • 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






  • 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













11














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.






share|improve this answer

























  • 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















11














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.






share|improve this answer

























  • 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













11












11








11







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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

















  • 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











0














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?






share|improve this answer


















  • 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
















0














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?






share|improve this answer


















  • 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














0












0








0







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?






share|improve this answer













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?







share|improve this answer












share|improve this answer



share|improve this answer










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 for std::toupper etc.

    – M.M
    Jul 4 at 9:06













  • 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








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


















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%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





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

Circuit construction for execution of conditional statements using least significant bitHow are two different registers being used as “control”?How exactly is the stated composite state of the two registers being produced using the $R_zz$ controlled rotations?Efficiently performing controlled rotations in HHLWould this quantum algorithm implementation work?How to prepare a superposed states of odd integers from $1$ to $sqrtN$?Why is this implementation of the order finding algorithm not working?Circuit construction for Hamiltonian simulationHow can I invert the least significant bit of a certain term of a superposed state?Implementing an oracleImplementing a controlled sum operation

Magento 2 “No Payment Methods” in Admin New OrderHow to integrate Paypal Express Checkout with the Magento APIMagento 1.5 - Sales > Order > edit order and shipping methods disappearAuto Invoice Check/Money Order Payment methodAdd more simple payment methods?Shipping methods not showingWhat should I do to change payment methods if changing the configuration has no effects?1.9 - No Payment Methods showing upMy Payment Methods not Showing for downloadable/virtual product when checkout?Magento2 API to access internal payment methodHow to call an existing payment methods in the registration form?