When does type information flow backwards in C++?











up vote
68
down vote

favorite
23












I just watched Stephan T. Lavavej talk at CppCon 2018 on "Class Template Argument Deduction", where at some point he incidentally says:




In C++ type information almost never flows backwards ... I had to say "almost" because there's one or two cases, possibly more but very few.




Despite trying to figure out which cases he might be referring to, I couldn't come up with anything. Hence the question:



In which cases the C++17 standard mandates that type information propagate backwards?










share|improve this question
























  • pattern matching partial specialization and destructuring assignments.
    – v.oddou
    2 days ago















up vote
68
down vote

favorite
23












I just watched Stephan T. Lavavej talk at CppCon 2018 on "Class Template Argument Deduction", where at some point he incidentally says:




In C++ type information almost never flows backwards ... I had to say "almost" because there's one or two cases, possibly more but very few.




Despite trying to figure out which cases he might be referring to, I couldn't come up with anything. Hence the question:



In which cases the C++17 standard mandates that type information propagate backwards?










share|improve this question
























  • pattern matching partial specialization and destructuring assignments.
    – v.oddou
    2 days ago













up vote
68
down vote

favorite
23









up vote
68
down vote

favorite
23






23





I just watched Stephan T. Lavavej talk at CppCon 2018 on "Class Template Argument Deduction", where at some point he incidentally says:




In C++ type information almost never flows backwards ... I had to say "almost" because there's one or two cases, possibly more but very few.




Despite trying to figure out which cases he might be referring to, I couldn't come up with anything. Hence the question:



In which cases the C++17 standard mandates that type information propagate backwards?










share|improve this question















I just watched Stephan T. Lavavej talk at CppCon 2018 on "Class Template Argument Deduction", where at some point he incidentally says:




In C++ type information almost never flows backwards ... I had to say "almost" because there's one or two cases, possibly more but very few.




Despite trying to figure out which cases he might be referring to, I couldn't come up with anything. Hence the question:



In which cases the C++17 standard mandates that type information propagate backwards?







c++ types language-lawyer c++17 type-deduction






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 52 mins ago









curiousguy

4,44322940




4,44322940










asked Nov 12 at 21:16









Massimiliano

5,22822851




5,22822851












  • pattern matching partial specialization and destructuring assignments.
    – v.oddou
    2 days ago


















  • pattern matching partial specialization and destructuring assignments.
    – v.oddou
    2 days ago
















pattern matching partial specialization and destructuring assignments.
– v.oddou
2 days ago




pattern matching partial specialization and destructuring assignments.
– v.oddou
2 days ago












3 Answers
3






active

oldest

votes

















up vote
65
down vote



accepted










Here is at least one case:



struct foo {
template<class T>
operator T() const {
std::cout << sizeof(T) << "n";
return {};
}
};


if you do foo f; int x = f; double y = f;, type information will flow "backwards" to figure out what T is in operator T.



You can use this in a more advanced way:



template<class T>
struct tag_t {using type=T;};

template<class F>
struct deduce_return_t {
F f;
template<class T>
operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); }
};
template<class F>
deduce_return_t(F&&)->deduce_return_t<F>;

template<class...Args>
auto construct_from( Args&&... args ) {
return deduce_return_t{ [&](auto ret){
using R=typename decltype(ret)::type;
return R{ std::forward<Args>(args)... };
}};
}


so now I can do



std::vector<int> v = construct_from( 1, 2, 3 );


and it works.



Of course, why not just do {1,2,3}? Well, {1,2,3} isn't an expression.



std::vector<std::vector<int>> v;
v.emplace_back( construct_from(1,2,3) );


which, admittedly, require a bit more wizardry: Live example. (I have to make the deduce return do a SFINAE check of F, then make the F be SFINAE friendly, and I have to block std::initializer_list in deduce_return_t operator T.)






share|improve this answer























  • Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
    – Massimiliano
    Nov 12 at 22:28






  • 4




    The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
    – Justin
    Nov 12 at 22:42










  • That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
    – liliscent
    2 days ago










  • @tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
    – Yakk - Adam Nevraumont
    2 days ago






  • 2




    @lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
    – Yakk - Adam Nevraumont
    2 days ago


















up vote
23
down vote













Stephan T. Lavavej explained the case he was talking about in a tweet:




The case I was thinking of is where you can take the address of an overloaded/templated function and if it’s being used to initialize a variable of a specific type, that will disambiguate which one you want. (There’s a list of what disambiguates.)




we can see examples of this from cppreference page on Address of overloaded function, I have excepted a few below:



int f(int) { return 1; } 
int f(double) { return 2; }

void g( int(&f1)(int), int(*f2)(double) ) {}

int main(){
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second

auto foo = () -> int (*)(int) {
return f; // selects int f(int)
};

auto p = static_cast<int(*)(int)>(f); // selects int f(int)
}


Michael Park adds:




It's not limited to initializing a concrete type, either. It could also infer just from the number of arguments




and provides this live example:



void overload(int, int) {}
void overload(int, int, int) {}

template <typename T1, typename T2,
typename A1, typename A2>
void f(void (*)(T1, T2), A1&&, A2&&) {}

template <typename T1, typename T2, typename T3,
typename A1, typename A2, typename A3>
void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {}

int main () {
f(&overload, 1, 2);
}


which I elaborate a little more here.






share|improve this answer



















  • 2




    We could also describe this as: cases where the type of an expression depends on the context?
    – M.M
    2 days ago


















up vote
16
down vote













I believe in static casting of overloaded functions the flow goes the opposite direction as in usual overload resolution. So one of those is backwards, I guess.






share|improve this answer

















  • 4




    I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
    – Yakk - Adam Nevraumont
    Nov 12 at 22:08











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',
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%2f53270242%2fwhen-does-type-information-flow-backwards-in-c%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








up vote
65
down vote



accepted










Here is at least one case:



struct foo {
template<class T>
operator T() const {
std::cout << sizeof(T) << "n";
return {};
}
};


if you do foo f; int x = f; double y = f;, type information will flow "backwards" to figure out what T is in operator T.



You can use this in a more advanced way:



template<class T>
struct tag_t {using type=T;};

template<class F>
struct deduce_return_t {
F f;
template<class T>
operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); }
};
template<class F>
deduce_return_t(F&&)->deduce_return_t<F>;

template<class...Args>
auto construct_from( Args&&... args ) {
return deduce_return_t{ [&](auto ret){
using R=typename decltype(ret)::type;
return R{ std::forward<Args>(args)... };
}};
}


so now I can do



std::vector<int> v = construct_from( 1, 2, 3 );


and it works.



Of course, why not just do {1,2,3}? Well, {1,2,3} isn't an expression.



std::vector<std::vector<int>> v;
v.emplace_back( construct_from(1,2,3) );


which, admittedly, require a bit more wizardry: Live example. (I have to make the deduce return do a SFINAE check of F, then make the F be SFINAE friendly, and I have to block std::initializer_list in deduce_return_t operator T.)






share|improve this answer























  • Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
    – Massimiliano
    Nov 12 at 22:28






  • 4




    The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
    – Justin
    Nov 12 at 22:42










  • That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
    – liliscent
    2 days ago










  • @tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
    – Yakk - Adam Nevraumont
    2 days ago






  • 2




    @lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
    – Yakk - Adam Nevraumont
    2 days ago















up vote
65
down vote



accepted










Here is at least one case:



struct foo {
template<class T>
operator T() const {
std::cout << sizeof(T) << "n";
return {};
}
};


if you do foo f; int x = f; double y = f;, type information will flow "backwards" to figure out what T is in operator T.



You can use this in a more advanced way:



template<class T>
struct tag_t {using type=T;};

template<class F>
struct deduce_return_t {
F f;
template<class T>
operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); }
};
template<class F>
deduce_return_t(F&&)->deduce_return_t<F>;

template<class...Args>
auto construct_from( Args&&... args ) {
return deduce_return_t{ [&](auto ret){
using R=typename decltype(ret)::type;
return R{ std::forward<Args>(args)... };
}};
}


so now I can do



std::vector<int> v = construct_from( 1, 2, 3 );


and it works.



Of course, why not just do {1,2,3}? Well, {1,2,3} isn't an expression.



std::vector<std::vector<int>> v;
v.emplace_back( construct_from(1,2,3) );


which, admittedly, require a bit more wizardry: Live example. (I have to make the deduce return do a SFINAE check of F, then make the F be SFINAE friendly, and I have to block std::initializer_list in deduce_return_t operator T.)






share|improve this answer























  • Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
    – Massimiliano
    Nov 12 at 22:28






  • 4




    The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
    – Justin
    Nov 12 at 22:42










  • That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
    – liliscent
    2 days ago










  • @tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
    – Yakk - Adam Nevraumont
    2 days ago






  • 2




    @lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
    – Yakk - Adam Nevraumont
    2 days ago













up vote
65
down vote



accepted







up vote
65
down vote



accepted






Here is at least one case:



struct foo {
template<class T>
operator T() const {
std::cout << sizeof(T) << "n";
return {};
}
};


if you do foo f; int x = f; double y = f;, type information will flow "backwards" to figure out what T is in operator T.



You can use this in a more advanced way:



template<class T>
struct tag_t {using type=T;};

template<class F>
struct deduce_return_t {
F f;
template<class T>
operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); }
};
template<class F>
deduce_return_t(F&&)->deduce_return_t<F>;

template<class...Args>
auto construct_from( Args&&... args ) {
return deduce_return_t{ [&](auto ret){
using R=typename decltype(ret)::type;
return R{ std::forward<Args>(args)... };
}};
}


so now I can do



std::vector<int> v = construct_from( 1, 2, 3 );


and it works.



Of course, why not just do {1,2,3}? Well, {1,2,3} isn't an expression.



std::vector<std::vector<int>> v;
v.emplace_back( construct_from(1,2,3) );


which, admittedly, require a bit more wizardry: Live example. (I have to make the deduce return do a SFINAE check of F, then make the F be SFINAE friendly, and I have to block std::initializer_list in deduce_return_t operator T.)






share|improve this answer














Here is at least one case:



struct foo {
template<class T>
operator T() const {
std::cout << sizeof(T) << "n";
return {};
}
};


if you do foo f; int x = f; double y = f;, type information will flow "backwards" to figure out what T is in operator T.



You can use this in a more advanced way:



template<class T>
struct tag_t {using type=T;};

template<class F>
struct deduce_return_t {
F f;
template<class T>
operator T()&&{ return std::forward<F>(f)(tag_t<T>{}); }
};
template<class F>
deduce_return_t(F&&)->deduce_return_t<F>;

template<class...Args>
auto construct_from( Args&&... args ) {
return deduce_return_t{ [&](auto ret){
using R=typename decltype(ret)::type;
return R{ std::forward<Args>(args)... };
}};
}


so now I can do



std::vector<int> v = construct_from( 1, 2, 3 );


and it works.



Of course, why not just do {1,2,3}? Well, {1,2,3} isn't an expression.



std::vector<std::vector<int>> v;
v.emplace_back( construct_from(1,2,3) );


which, admittedly, require a bit more wizardry: Live example. (I have to make the deduce return do a SFINAE check of F, then make the F be SFINAE friendly, and I have to block std::initializer_list in deduce_return_t operator T.)







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered Nov 12 at 21:26









Yakk - Adam Nevraumont

177k19182362




177k19182362












  • Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
    – Massimiliano
    Nov 12 at 22:28






  • 4




    The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
    – Justin
    Nov 12 at 22:42










  • That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
    – liliscent
    2 days ago










  • @tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
    – Yakk - Adam Nevraumont
    2 days ago






  • 2




    @lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
    – Yakk - Adam Nevraumont
    2 days ago


















  • Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
    – Massimiliano
    Nov 12 at 22:28






  • 4




    The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
    – Justin
    Nov 12 at 22:42










  • That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
    – liliscent
    2 days ago










  • @tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
    – Yakk - Adam Nevraumont
    2 days ago






  • 2




    @lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
    – Yakk - Adam Nevraumont
    2 days ago
















Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
– Massimiliano
Nov 12 at 22:28




Very interesting answer, and I learned a new trick so thank you very much! I had to add a template deduction guideline to make your example compile, but other than that it works like a charm!
– Massimiliano
Nov 12 at 22:28




4




4




The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
– Justin
Nov 12 at 22:42




The && qualifier on the operator T() is a great touch; it helps avoid the poor interaction with auto by causing a compilation error if auto is misused here.
– Justin
Nov 12 at 22:42












That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
– liliscent
2 days ago




That's very impressive, could you point me to some reference/talk to the idea in the example? or maybe it's original :) ...
– liliscent
2 days ago












@tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
– Yakk - Adam Nevraumont
2 days ago




@tootsie No, it is an aggregate, and I used {}. I may need a deduction guide but I'm uncertain. Please note you could do this in 4 times the code and be twice as clear; I was being terse in my adding of a new language feature as a header file #include here.
– Yakk - Adam Nevraumont
2 days ago




2




2




@lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
– Yakk - Adam Nevraumont
2 days ago




@lili Which idea? I count 5: Using operator T to deduce return types? Using tags to pass the deduced type to a lambda? Using conversion operators to roll-your-own placement object construction? Connecting all 4?
– Yakk - Adam Nevraumont
2 days ago












up vote
23
down vote













Stephan T. Lavavej explained the case he was talking about in a tweet:




The case I was thinking of is where you can take the address of an overloaded/templated function and if it’s being used to initialize a variable of a specific type, that will disambiguate which one you want. (There’s a list of what disambiguates.)




we can see examples of this from cppreference page on Address of overloaded function, I have excepted a few below:



int f(int) { return 1; } 
int f(double) { return 2; }

void g( int(&f1)(int), int(*f2)(double) ) {}

int main(){
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second

auto foo = () -> int (*)(int) {
return f; // selects int f(int)
};

auto p = static_cast<int(*)(int)>(f); // selects int f(int)
}


Michael Park adds:




It's not limited to initializing a concrete type, either. It could also infer just from the number of arguments




and provides this live example:



void overload(int, int) {}
void overload(int, int, int) {}

template <typename T1, typename T2,
typename A1, typename A2>
void f(void (*)(T1, T2), A1&&, A2&&) {}

template <typename T1, typename T2, typename T3,
typename A1, typename A2, typename A3>
void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {}

int main () {
f(&overload, 1, 2);
}


which I elaborate a little more here.






share|improve this answer



















  • 2




    We could also describe this as: cases where the type of an expression depends on the context?
    – M.M
    2 days ago















up vote
23
down vote













Stephan T. Lavavej explained the case he was talking about in a tweet:




The case I was thinking of is where you can take the address of an overloaded/templated function and if it’s being used to initialize a variable of a specific type, that will disambiguate which one you want. (There’s a list of what disambiguates.)




we can see examples of this from cppreference page on Address of overloaded function, I have excepted a few below:



int f(int) { return 1; } 
int f(double) { return 2; }

void g( int(&f1)(int), int(*f2)(double) ) {}

int main(){
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second

auto foo = () -> int (*)(int) {
return f; // selects int f(int)
};

auto p = static_cast<int(*)(int)>(f); // selects int f(int)
}


Michael Park adds:




It's not limited to initializing a concrete type, either. It could also infer just from the number of arguments




and provides this live example:



void overload(int, int) {}
void overload(int, int, int) {}

template <typename T1, typename T2,
typename A1, typename A2>
void f(void (*)(T1, T2), A1&&, A2&&) {}

template <typename T1, typename T2, typename T3,
typename A1, typename A2, typename A3>
void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {}

int main () {
f(&overload, 1, 2);
}


which I elaborate a little more here.






share|improve this answer



















  • 2




    We could also describe this as: cases where the type of an expression depends on the context?
    – M.M
    2 days ago













up vote
23
down vote










up vote
23
down vote









Stephan T. Lavavej explained the case he was talking about in a tweet:




The case I was thinking of is where you can take the address of an overloaded/templated function and if it’s being used to initialize a variable of a specific type, that will disambiguate which one you want. (There’s a list of what disambiguates.)




we can see examples of this from cppreference page on Address of overloaded function, I have excepted a few below:



int f(int) { return 1; } 
int f(double) { return 2; }

void g( int(&f1)(int), int(*f2)(double) ) {}

int main(){
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second

auto foo = () -> int (*)(int) {
return f; // selects int f(int)
};

auto p = static_cast<int(*)(int)>(f); // selects int f(int)
}


Michael Park adds:




It's not limited to initializing a concrete type, either. It could also infer just from the number of arguments




and provides this live example:



void overload(int, int) {}
void overload(int, int, int) {}

template <typename T1, typename T2,
typename A1, typename A2>
void f(void (*)(T1, T2), A1&&, A2&&) {}

template <typename T1, typename T2, typename T3,
typename A1, typename A2, typename A3>
void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {}

int main () {
f(&overload, 1, 2);
}


which I elaborate a little more here.






share|improve this answer














Stephan T. Lavavej explained the case he was talking about in a tweet:




The case I was thinking of is where you can take the address of an overloaded/templated function and if it’s being used to initialize a variable of a specific type, that will disambiguate which one you want. (There’s a list of what disambiguates.)




we can see examples of this from cppreference page on Address of overloaded function, I have excepted a few below:



int f(int) { return 1; } 
int f(double) { return 2; }

void g( int(&f1)(int), int(*f2)(double) ) {}

int main(){
g(f, f); // selects int f(int) for the 1st argument
// and int f(double) for the second

auto foo = () -> int (*)(int) {
return f; // selects int f(int)
};

auto p = static_cast<int(*)(int)>(f); // selects int f(int)
}


Michael Park adds:




It's not limited to initializing a concrete type, either. It could also infer just from the number of arguments




and provides this live example:



void overload(int, int) {}
void overload(int, int, int) {}

template <typename T1, typename T2,
typename A1, typename A2>
void f(void (*)(T1, T2), A1&&, A2&&) {}

template <typename T1, typename T2, typename T3,
typename A1, typename A2, typename A3>
void f(void (*)(T1, T2, T3), A1&&, A2&&, A3&&) {}

int main () {
f(&overload, 1, 2);
}


which I elaborate a little more here.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered 2 days ago









Shafik Yaghmour

122k23305509




122k23305509








  • 2




    We could also describe this as: cases where the type of an expression depends on the context?
    – M.M
    2 days ago














  • 2




    We could also describe this as: cases where the type of an expression depends on the context?
    – M.M
    2 days ago








2




2




We could also describe this as: cases where the type of an expression depends on the context?
– M.M
2 days ago




We could also describe this as: cases where the type of an expression depends on the context?
– M.M
2 days ago










up vote
16
down vote













I believe in static casting of overloaded functions the flow goes the opposite direction as in usual overload resolution. So one of those is backwards, I guess.






share|improve this answer

















  • 4




    I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
    – Yakk - Adam Nevraumont
    Nov 12 at 22:08















up vote
16
down vote













I believe in static casting of overloaded functions the flow goes the opposite direction as in usual overload resolution. So one of those is backwards, I guess.






share|improve this answer

















  • 4




    I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
    – Yakk - Adam Nevraumont
    Nov 12 at 22:08













up vote
16
down vote










up vote
16
down vote









I believe in static casting of overloaded functions the flow goes the opposite direction as in usual overload resolution. So one of those is backwards, I guess.






share|improve this answer












I believe in static casting of overloaded functions the flow goes the opposite direction as in usual overload resolution. So one of those is backwards, I guess.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 12 at 21:19









jbapple

2,6111630




2,6111630








  • 4




    I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
    – Yakk - Adam Nevraumont
    Nov 12 at 22:08














  • 4




    I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
    – Yakk - Adam Nevraumont
    Nov 12 at 22:08








4




4




I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
– Yakk - Adam Nevraumont
Nov 12 at 22:08




I believe this is correct. And it is when you pass a function name to a function pointer type; type information flows from the context of the expression (the type you are assigning to/constructing/etc) backwards into the name of the function to determine which overload is chosen.
– Yakk - Adam Nevraumont
Nov 12 at 22:08


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270242%2fwhen-does-type-information-flow-backwards-in-c%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

Plaza Victoria

Puebla de Zaragoza

Musa