When does type information flow backwards in C++?











up vote
62
down vote

favorite
19












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
    22 hours ago















up vote
62
down vote

favorite
19












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
    22 hours ago













up vote
62
down vote

favorite
19









up vote
62
down vote

favorite
19






19





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++ language-lawyer c++17






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 7 hours ago









scohe001

7,57612141




7,57612141










asked yesterday









Massimiliano

5,19622851




5,19622851












  • pattern matching partial specialization and destructuring assignments.
    – v.oddou
    22 hours ago


















  • pattern matching partial specialization and destructuring assignments.
    – v.oddou
    22 hours ago
















pattern matching partial specialization and destructuring assignments.
– v.oddou
22 hours ago




pattern matching partial specialization and destructuring assignments.
– v.oddou
22 hours ago












3 Answers
3






active

oldest

votes

















up vote
59
down vote













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
    yesterday






  • 2




    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
    yesterday










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










  • @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
    yesterday






  • 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
    yesterday


















up vote
20
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
    yesterday


















up vote
12
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
    yesterday











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
































3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
59
down vote













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
    yesterday






  • 2




    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
    yesterday










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










  • @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
    yesterday






  • 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
    yesterday















up vote
59
down vote













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
    yesterday






  • 2




    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
    yesterday










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










  • @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
    yesterday






  • 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
    yesterday













up vote
59
down vote










up vote
59
down vote









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 12 hours ago

























answered yesterday









Yakk - Adam Nevraumont

177k19181362




177k19181362












  • 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
    yesterday






  • 2




    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
    yesterday










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










  • @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
    yesterday






  • 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
    yesterday


















  • 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
    yesterday






  • 2




    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
    yesterday










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










  • @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
    yesterday






  • 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
    yesterday
















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
yesterday




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
yesterday




2




2




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
yesterday




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
yesterday












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




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












@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
yesterday




@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
yesterday




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
yesterday




@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
yesterday












up vote
20
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
    yesterday















up vote
20
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
    yesterday













up vote
20
down vote










up vote
20
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 13 hours ago

























answered yesterday









Shafik Yaghmour

122k23305509




122k23305509








  • 2




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














  • 2




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








2




2




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




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










up vote
12
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
    yesterday















up vote
12
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
    yesterday













up vote
12
down vote










up vote
12
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 yesterday









jbapple

2,5711630




2,5711630








  • 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
    yesterday














  • 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
    yesterday








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
yesterday




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
yesterday


















 

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




















































































Popular posts from this blog

How do I know what Microsoft account the skydrive app is syncing to?

Grease: Live!