Substitution failure with `std::function` and previously deduced template parameter - why?Why can templates only be implemented in the header file?Where and why do I have to put the “template” and “typename” keywords?Why is “using namespace std;” considered bad practice?Are the days of passing const std::string & as a parameter over?Why do auto and template type deduction differ for braced initializers?Why does the order of template argument substitution matter?Why can't the compiler deduce my template value from the function argument?Cannot deduce template parameter 'N'Why can't unique_ptr's template arguments be deduced?
Substitution failure with `std::function` and previously deduced template parameter - why?
Is it unethical to give a gift to my professor who might potentially write me a LOR?
I've been fired, was allowed to announce it as if I quit and given extra notice, how to handle the questions?
When can I access the friends list in Mario Kart Tour?
Non-electric Laser
Was there an autocomplete utility in MS-DOS?
What would the EU’s position be with respect to a United Ireland?
Determining if auto stats update is in progress
Using 4K Skyrim Textures when running 1920 x 1080 display resolution?
Sum of series with addition
When using PWM, what is the purpose of having two complimentary square waves on the same channel?
Why is my vegetable stock bitter, but the chicken stock not?
Did the Soviet army intentionally send troops (e.g. penal battalions) running over minefields?
Would houseruling two or more instances of resistance to the same element as immunity be overly unbalanced?
Why do many websites hide input when entering a OTP
How Concerning Is This X-CU-modified: FAKECU Text Attack?
Search for something difficult to count/estimate
The answer is the same (tricky puzzle!)
What's the difference between motherboard and chassis?
Angle between a vector and cross product of two vectors
How does case-insensitive collation work?
Is right click on tables bad UX
What benefits are there to blocking most search engines?
How is the speed of nucleons in the nucleus measured?
Substitution failure with `std::function` and previously deduced template parameter - why?
Why can templates only be implemented in the header file?Where and why do I have to put the “template” and “typename” keywords?Why is “using namespace std;” considered bad practice?Are the days of passing const std::string & as a parameter over?Why do auto and template type deduction differ for braced initializers?Why does the order of template argument substitution matter?Why can't the compiler deduce my template value from the function argument?Cannot deduce template parameter 'N'Why can't unique_ptr's template arguments be deduced?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
Consider the following code:
template <typename>
struct S ;
void g(S<int> t);
template <typename T>
void f(T, std::function<void(S<T>)>);
When attempting to invoke
f(0, g);
I get the following error:
error: no matching function for call to 'f'
f(0, g);
^
note: candidate template ignored: could not match
'function<void (S<type-parameter-0-0>)>'
against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
^
live example on godbolt.org
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
In this case T can first be deduced by the passed argument 0, and then substituted into std::function<void(S<T>)> to get std::function<void(S<int>)>.
I would expect that after deducing T=int, the compiler would substitute T everywhere in the signature and then attempt to construct the std::function parameter with the argument g.
Why is that not the case? I presume that the ordering in which substitution/deduction happens has something to do with this, but I'd like to see the relevant Standard wording.
Bonus question: is this something that could potentially be changed in a future Standard while preserving backwards compatibility, or is there a fundamental reason why this kind of substitution doesn't work?
c++ c++11 templates language-lawyer template-deduction
add a comment
|
Consider the following code:
template <typename>
struct S ;
void g(S<int> t);
template <typename T>
void f(T, std::function<void(S<T>)>);
When attempting to invoke
f(0, g);
I get the following error:
error: no matching function for call to 'f'
f(0, g);
^
note: candidate template ignored: could not match
'function<void (S<type-parameter-0-0>)>'
against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
^
live example on godbolt.org
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
In this case T can first be deduced by the passed argument 0, and then substituted into std::function<void(S<T>)> to get std::function<void(S<int>)>.
I would expect that after deducing T=int, the compiler would substitute T everywhere in the signature and then attempt to construct the std::function parameter with the argument g.
Why is that not the case? I presume that the ordering in which substitution/deduction happens has something to do with this, but I'd like to see the relevant Standard wording.
Bonus question: is this something that could potentially be changed in a future Standard while preserving backwards compatibility, or is there a fundamental reason why this kind of substitution doesn't work?
c++ c++11 templates language-lawyer template-deduction
3
Here is the same thing withoutstd::functionor function pointers, to simplify a bit: gcc.godbolt.org/z/SHXtwh
– Max Langhof
10 hours ago
You can still usetemplate <typename T> void f(T, std::identity_type_t<std::function<void(S<T>)>>).
– Jarod42
9 hours ago
@Jarod42 Isstd::identity_type_tup for standardization?
– Max Langhof
9 hours ago
@MaxLanghof en.cppreference.com/w/cpp/types/type_identity
– Vittorio Romeo
9 hours ago
add a comment
|
Consider the following code:
template <typename>
struct S ;
void g(S<int> t);
template <typename T>
void f(T, std::function<void(S<T>)>);
When attempting to invoke
f(0, g);
I get the following error:
error: no matching function for call to 'f'
f(0, g);
^
note: candidate template ignored: could not match
'function<void (S<type-parameter-0-0>)>'
against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
^
live example on godbolt.org
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
In this case T can first be deduced by the passed argument 0, and then substituted into std::function<void(S<T>)> to get std::function<void(S<int>)>.
I would expect that after deducing T=int, the compiler would substitute T everywhere in the signature and then attempt to construct the std::function parameter with the argument g.
Why is that not the case? I presume that the ordering in which substitution/deduction happens has something to do with this, but I'd like to see the relevant Standard wording.
Bonus question: is this something that could potentially be changed in a future Standard while preserving backwards compatibility, or is there a fundamental reason why this kind of substitution doesn't work?
c++ c++11 templates language-lawyer template-deduction
Consider the following code:
template <typename>
struct S ;
void g(S<int> t);
template <typename T>
void f(T, std::function<void(S<T>)>);
When attempting to invoke
f(0, g);
I get the following error:
error: no matching function for call to 'f'
f(0, g);
^
note: candidate template ignored: could not match
'function<void (S<type-parameter-0-0>)>'
against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
^
live example on godbolt.org
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
In this case T can first be deduced by the passed argument 0, and then substituted into std::function<void(S<T>)> to get std::function<void(S<int>)>.
I would expect that after deducing T=int, the compiler would substitute T everywhere in the signature and then attempt to construct the std::function parameter with the argument g.
Why is that not the case? I presume that the ordering in which substitution/deduction happens has something to do with this, but I'd like to see the relevant Standard wording.
Bonus question: is this something that could potentially be changed in a future Standard while preserving backwards compatibility, or is there a fundamental reason why this kind of substitution doesn't work?
c++ c++11 templates language-lawyer template-deduction
c++ c++11 templates language-lawyer template-deduction
edited 9 hours ago
Vittorio Romeo
asked 10 hours ago
Vittorio RomeoVittorio Romeo
64.9k18 gold badges180 silver badges336 bronze badges
64.9k18 gold badges180 silver badges336 bronze badges
3
Here is the same thing withoutstd::functionor function pointers, to simplify a bit: gcc.godbolt.org/z/SHXtwh
– Max Langhof
10 hours ago
You can still usetemplate <typename T> void f(T, std::identity_type_t<std::function<void(S<T>)>>).
– Jarod42
9 hours ago
@Jarod42 Isstd::identity_type_tup for standardization?
– Max Langhof
9 hours ago
@MaxLanghof en.cppreference.com/w/cpp/types/type_identity
– Vittorio Romeo
9 hours ago
add a comment
|
3
Here is the same thing withoutstd::functionor function pointers, to simplify a bit: gcc.godbolt.org/z/SHXtwh
– Max Langhof
10 hours ago
You can still usetemplate <typename T> void f(T, std::identity_type_t<std::function<void(S<T>)>>).
– Jarod42
9 hours ago
@Jarod42 Isstd::identity_type_tup for standardization?
– Max Langhof
9 hours ago
@MaxLanghof en.cppreference.com/w/cpp/types/type_identity
– Vittorio Romeo
9 hours ago
3
3
Here is the same thing without
std::function or function pointers, to simplify a bit: gcc.godbolt.org/z/SHXtwh– Max Langhof
10 hours ago
Here is the same thing without
std::function or function pointers, to simplify a bit: gcc.godbolt.org/z/SHXtwh– Max Langhof
10 hours ago
You can still use
template <typename T> void f(T, std::identity_type_t<std::function<void(S<T>)>>).– Jarod42
9 hours ago
You can still use
template <typename T> void f(T, std::identity_type_t<std::function<void(S<T>)>>).– Jarod42
9 hours ago
@Jarod42 Is
std::identity_type_t up for standardization?– Max Langhof
9 hours ago
@Jarod42 Is
std::identity_type_t up for standardization?– Max Langhof
9 hours ago
@MaxLanghof en.cppreference.com/w/cpp/types/type_identity
– Vittorio Romeo
9 hours ago
@MaxLanghof en.cppreference.com/w/cpp/types/type_identity
– Vittorio Romeo
9 hours ago
add a comment
|
2 Answers
2
active
oldest
votes
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
It is not a non-deduced context. Quite the contrary. Because deduction for the parameter of std::funcition is attempted, but the argument is not a std::function, deduction fails. The deduction of template arguments from function arguments must agree for all function arguments. If it fails for one, it fails entirely.
[temp.deduct.type]
2 In some cases, the deduction is done using a single set of
types P and A, in other cases, there will be a set of corresponding
types P and A. Type deduction is done independently for each P/A pair,
and the deduced template argument values are then combined. If type
deduction cannot be done for any P/A pair, or if for any pair the
deduction leads to more than one possible set of deduced values, or if
different pairs yield different deduced values, or if any template
argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error:
#include <functional>
template<typename T>
struct type_identity
using type = T;
;
template <typename>
struct S ;
void g(S<int> )
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type)
int main()
f(0, g);
T is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.
Live
add a comment
|
While I understand that generally the type of the
std::functionparameter can't be deduced as it is a non-deduced context, in this caseTcan first be deduced by the passed argument0.
This is not true. T is deduceable in this context. If you change the code to
template <typename T>
void f(std::function<void(S<T>)>);
int main()
f(std::function<void(S<int>)>(g));
the code would compile and T is correctly deduced.
Your issue is that you are passing an object to the function that it can't extract T from. The compiler will not do any conversion of the function arguments when it tries to deduce T. That means you have a int and a function as the types passed to the function. It gets int from 0, then tries to get the type from the std::function you pass in the second parameter but since you didn't pass a std::function it can't extract T and because of that, you get an error.
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.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
);
);
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
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58135939%2fsubstitution-failure-with-stdfunction-and-previously-deduced-template-parame%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
It is not a non-deduced context. Quite the contrary. Because deduction for the parameter of std::funcition is attempted, but the argument is not a std::function, deduction fails. The deduction of template arguments from function arguments must agree for all function arguments. If it fails for one, it fails entirely.
[temp.deduct.type]
2 In some cases, the deduction is done using a single set of
types P and A, in other cases, there will be a set of corresponding
types P and A. Type deduction is done independently for each P/A pair,
and the deduced template argument values are then combined. If type
deduction cannot be done for any P/A pair, or if for any pair the
deduction leads to more than one possible set of deduced values, or if
different pairs yield different deduced values, or if any template
argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error:
#include <functional>
template<typename T>
struct type_identity
using type = T;
;
template <typename>
struct S ;
void g(S<int> )
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type)
int main()
f(0, g);
T is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.
Live
add a comment
|
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
It is not a non-deduced context. Quite the contrary. Because deduction for the parameter of std::funcition is attempted, but the argument is not a std::function, deduction fails. The deduction of template arguments from function arguments must agree for all function arguments. If it fails for one, it fails entirely.
[temp.deduct.type]
2 In some cases, the deduction is done using a single set of
types P and A, in other cases, there will be a set of corresponding
types P and A. Type deduction is done independently for each P/A pair,
and the deduced template argument values are then combined. If type
deduction cannot be done for any P/A pair, or if for any pair the
deduction leads to more than one possible set of deduced values, or if
different pairs yield different deduced values, or if any template
argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error:
#include <functional>
template<typename T>
struct type_identity
using type = T;
;
template <typename>
struct S ;
void g(S<int> )
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type)
int main()
f(0, g);
T is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.
Live
add a comment
|
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
It is not a non-deduced context. Quite the contrary. Because deduction for the parameter of std::funcition is attempted, but the argument is not a std::function, deduction fails. The deduction of template arguments from function arguments must agree for all function arguments. If it fails for one, it fails entirely.
[temp.deduct.type]
2 In some cases, the deduction is done using a single set of
types P and A, in other cases, there will be a set of corresponding
types P and A. Type deduction is done independently for each P/A pair,
and the deduced template argument values are then combined. If type
deduction cannot be done for any P/A pair, or if for any pair the
deduction leads to more than one possible set of deduced values, or if
different pairs yield different deduced values, or if any template
argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error:
#include <functional>
template<typename T>
struct type_identity
using type = T;
;
template <typename>
struct S ;
void g(S<int> )
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type)
int main()
f(0, g);
T is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.
Live
While I understand that generally the type of the std::function parameter can't be deduced as it is a non-deduced context
It is not a non-deduced context. Quite the contrary. Because deduction for the parameter of std::funcition is attempted, but the argument is not a std::function, deduction fails. The deduction of template arguments from function arguments must agree for all function arguments. If it fails for one, it fails entirely.
[temp.deduct.type]
2 In some cases, the deduction is done using a single set of
types P and A, in other cases, there will be a set of corresponding
types P and A. Type deduction is done independently for each P/A pair,
and the deduced template argument values are then combined. If type
deduction cannot be done for any P/A pair, or if for any pair the
deduction leads to more than one possible set of deduced values, or if
different pairs yield different deduced values, or if any template
argument remains neither deduced nor explicitly specified, template
argument deduction fails.
Making the type of the second function parameter into a non-deduced context is actually how one can overcome the error:
#include <functional>
template<typename T>
struct type_identity
using type = T;
;
template <typename>
struct S ;
void g(S<int> )
template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type)
int main()
f(0, g);
T is deduced successfully from the first function argument, and there is nothing left to deduce. So the dedcution is deemed a success.
Live
edited 9 hours ago
answered 9 hours ago
StoryTellerStoryTeller
121k18 gold badges260 silver badges327 bronze badges
121k18 gold badges260 silver badges327 bronze badges
add a comment
|
add a comment
|
While I understand that generally the type of the
std::functionparameter can't be deduced as it is a non-deduced context, in this caseTcan first be deduced by the passed argument0.
This is not true. T is deduceable in this context. If you change the code to
template <typename T>
void f(std::function<void(S<T>)>);
int main()
f(std::function<void(S<int>)>(g));
the code would compile and T is correctly deduced.
Your issue is that you are passing an object to the function that it can't extract T from. The compiler will not do any conversion of the function arguments when it tries to deduce T. That means you have a int and a function as the types passed to the function. It gets int from 0, then tries to get the type from the std::function you pass in the second parameter but since you didn't pass a std::function it can't extract T and because of that, you get an error.
add a comment
|
While I understand that generally the type of the
std::functionparameter can't be deduced as it is a non-deduced context, in this caseTcan first be deduced by the passed argument0.
This is not true. T is deduceable in this context. If you change the code to
template <typename T>
void f(std::function<void(S<T>)>);
int main()
f(std::function<void(S<int>)>(g));
the code would compile and T is correctly deduced.
Your issue is that you are passing an object to the function that it can't extract T from. The compiler will not do any conversion of the function arguments when it tries to deduce T. That means you have a int and a function as the types passed to the function. It gets int from 0, then tries to get the type from the std::function you pass in the second parameter but since you didn't pass a std::function it can't extract T and because of that, you get an error.
add a comment
|
While I understand that generally the type of the
std::functionparameter can't be deduced as it is a non-deduced context, in this caseTcan first be deduced by the passed argument0.
This is not true. T is deduceable in this context. If you change the code to
template <typename T>
void f(std::function<void(S<T>)>);
int main()
f(std::function<void(S<int>)>(g));
the code would compile and T is correctly deduced.
Your issue is that you are passing an object to the function that it can't extract T from. The compiler will not do any conversion of the function arguments when it tries to deduce T. That means you have a int and a function as the types passed to the function. It gets int from 0, then tries to get the type from the std::function you pass in the second parameter but since you didn't pass a std::function it can't extract T and because of that, you get an error.
While I understand that generally the type of the
std::functionparameter can't be deduced as it is a non-deduced context, in this caseTcan first be deduced by the passed argument0.
This is not true. T is deduceable in this context. If you change the code to
template <typename T>
void f(std::function<void(S<T>)>);
int main()
f(std::function<void(S<int>)>(g));
the code would compile and T is correctly deduced.
Your issue is that you are passing an object to the function that it can't extract T from. The compiler will not do any conversion of the function arguments when it tries to deduce T. That means you have a int and a function as the types passed to the function. It gets int from 0, then tries to get the type from the std::function you pass in the second parameter but since you didn't pass a std::function it can't extract T and because of that, you get an error.
answered 9 hours ago
NathanOliverNathanOliver
116k19 gold badges185 silver badges264 bronze badges
116k19 gold badges185 silver badges264 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58135939%2fsubstitution-failure-with-stdfunction-and-previously-deduced-template-parame%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
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
Required, but never shown
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
Required, but never shown
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
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
3
Here is the same thing without
std::functionor function pointers, to simplify a bit: gcc.godbolt.org/z/SHXtwh– Max Langhof
10 hours ago
You can still use
template <typename T> void f(T, std::identity_type_t<std::function<void(S<T>)>>).– Jarod42
9 hours ago
@Jarod42 Is
std::identity_type_tup for standardization?– Max Langhof
9 hours ago
@MaxLanghof en.cppreference.com/w/cpp/types/type_identity
– Vittorio Romeo
9 hours ago