When does type information flow backwards in C++?
up vote
68
down vote
favorite
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
add a comment |
up vote
68
down vote
favorite
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
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday
add a comment |
up vote
68
down vote
favorite
up vote
68
down vote
favorite
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
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
c++ language-lawyer c++17
edited yesterday
scohe001
7,57612141
7,57612141
asked 2 days ago
Massimiliano
5,22822851
5,22822851
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday
add a comment |
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday
add a comment |
3 Answers
3
active
oldest
votes
up vote
63
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.)
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
2 days ago
3
The&&
qualifier on theoperator T()
is a great touch; it helps avoid the poor interaction withauto
by causing a compilation error ifauto
is misused here.
– Justin
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
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
|
show 5 more comments
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.
2
We could also describe this as: cases where the type of an expression depends on the context?
– M.M
2 days ago
add a comment |
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.
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
2 days ago
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
63
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.)
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
2 days ago
3
The&&
qualifier on theoperator T()
is a great touch; it helps avoid the poor interaction withauto
by causing a compilation error ifauto
is misused here.
– Justin
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
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
|
show 5 more comments
up vote
63
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.)
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
2 days ago
3
The&&
qualifier on theoperator T()
is a great touch; it helps avoid the poor interaction withauto
by causing a compilation error ifauto
is misused here.
– Justin
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
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
|
show 5 more comments
up vote
63
down vote
accepted
up vote
63
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.)
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.)
edited yesterday
answered 2 days ago
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
2 days ago
3
The&&
qualifier on theoperator T()
is a great touch; it helps avoid the poor interaction withauto
by causing a compilation error ifauto
is misused here.
– Justin
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
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
|
show 5 more comments
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
2 days ago
3
The&&
qualifier on theoperator T()
is a great touch; it helps avoid the poor interaction withauto
by causing a compilation error ifauto
is misused here.
– Justin
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
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
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
2 days ago
3
3
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
2 days ago
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
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
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
|
show 5 more comments
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.
2
We could also describe this as: cases where the type of an expression depends on the context?
– M.M
2 days ago
add a comment |
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.
2
We could also describe this as: cases where the type of an expression depends on the context?
– M.M
2 days ago
add a comment |
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.
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.
edited yesterday
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
add a comment |
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
add a comment |
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.
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
2 days ago
add a comment |
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.
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
2 days ago
add a comment |
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.
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.
answered 2 days ago
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
2 days ago
add a comment |
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
2 days ago
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
2 days ago
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
2 days ago
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday