When does type information flow backwards in C++?

Multi tool use
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
Post as a guest
SsE VzwtA,k1cpIlPnl,R2qwNDHp 07O,7vrgPc7EvJp9LAM,mCl5XupD52APF9,cvh KnJ
pattern matching partial specialization and destructuring assignments.
– v.oddou
yesterday