Why does the implicit type conversion not work in template deduction?
up vote
12
down vote
favorite
In the following code, I want to call a template function by implicitly converting an int
to a Scalar<int>
object.
#include<iostream>
using namespace std;
template<typename Dtype>
class Scalar{
public:
Scalar(Dtype v) : value_(v){}
private:
Dtype value_;
};
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
int main(){
int a = 1;
func(a, 2);
//int b = 2;
//func(a, b);
return 0;
}
Why does the template argument deduction/substitution fail? And the commented-codes are also wrong.
test.cpp: In function ‘int main()’:
test.cpp:19:12: error: no matching function for call to ‘func(int&, int)’
func(a, 2);
^
test.cpp:19:12: note: candidate is:
test.cpp:13:6: note: template<class Dtype> void func(int, Scalar<Dtype>)
void func(int a, Scalar<Dtype> b){
^
test.cpp:13:6: note: template argument deduction/substitution failed:
test.cpp:19:12: note: mismatched types ‘Scalar<Dtype>’ and ‘int’
func(a, 2);
c++ c++11 templates
add a comment |
up vote
12
down vote
favorite
In the following code, I want to call a template function by implicitly converting an int
to a Scalar<int>
object.
#include<iostream>
using namespace std;
template<typename Dtype>
class Scalar{
public:
Scalar(Dtype v) : value_(v){}
private:
Dtype value_;
};
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
int main(){
int a = 1;
func(a, 2);
//int b = 2;
//func(a, b);
return 0;
}
Why does the template argument deduction/substitution fail? And the commented-codes are also wrong.
test.cpp: In function ‘int main()’:
test.cpp:19:12: error: no matching function for call to ‘func(int&, int)’
func(a, 2);
^
test.cpp:19:12: note: candidate is:
test.cpp:13:6: note: template<class Dtype> void func(int, Scalar<Dtype>)
void func(int a, Scalar<Dtype> b){
^
test.cpp:13:6: note: template argument deduction/substitution failed:
test.cpp:19:12: note: mismatched types ‘Scalar<Dtype>’ and ‘int’
func(a, 2);
c++ c++11 templates
4
Possible duplicate of C++ implicit type conversion with template
– jwismar
Nov 9 at 14:38
add a comment |
up vote
12
down vote
favorite
up vote
12
down vote
favorite
In the following code, I want to call a template function by implicitly converting an int
to a Scalar<int>
object.
#include<iostream>
using namespace std;
template<typename Dtype>
class Scalar{
public:
Scalar(Dtype v) : value_(v){}
private:
Dtype value_;
};
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
int main(){
int a = 1;
func(a, 2);
//int b = 2;
//func(a, b);
return 0;
}
Why does the template argument deduction/substitution fail? And the commented-codes are also wrong.
test.cpp: In function ‘int main()’:
test.cpp:19:12: error: no matching function for call to ‘func(int&, int)’
func(a, 2);
^
test.cpp:19:12: note: candidate is:
test.cpp:13:6: note: template<class Dtype> void func(int, Scalar<Dtype>)
void func(int a, Scalar<Dtype> b){
^
test.cpp:13:6: note: template argument deduction/substitution failed:
test.cpp:19:12: note: mismatched types ‘Scalar<Dtype>’ and ‘int’
func(a, 2);
c++ c++11 templates
In the following code, I want to call a template function by implicitly converting an int
to a Scalar<int>
object.
#include<iostream>
using namespace std;
template<typename Dtype>
class Scalar{
public:
Scalar(Dtype v) : value_(v){}
private:
Dtype value_;
};
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
int main(){
int a = 1;
func(a, 2);
//int b = 2;
//func(a, b);
return 0;
}
Why does the template argument deduction/substitution fail? And the commented-codes are also wrong.
test.cpp: In function ‘int main()’:
test.cpp:19:12: error: no matching function for call to ‘func(int&, int)’
func(a, 2);
^
test.cpp:19:12: note: candidate is:
test.cpp:13:6: note: template<class Dtype> void func(int, Scalar<Dtype>)
void func(int a, Scalar<Dtype> b){
^
test.cpp:13:6: note: template argument deduction/substitution failed:
test.cpp:19:12: note: mismatched types ‘Scalar<Dtype>’ and ‘int’
func(a, 2);
c++ c++11 templates
c++ c++11 templates
edited Nov 9 at 14:46
YSC
20.3k34593
20.3k34593
asked Nov 9 at 14:33
Yulong Ao
455617
455617
4
Possible duplicate of C++ implicit type conversion with template
– jwismar
Nov 9 at 14:38
add a comment |
4
Possible duplicate of C++ implicit type conversion with template
– jwismar
Nov 9 at 14:38
4
4
Possible duplicate of C++ implicit type conversion with template
– jwismar
Nov 9 at 14:38
Possible duplicate of C++ implicit type conversion with template
– jwismar
Nov 9 at 14:38
add a comment |
2 Answers
2
active
oldest
votes
up vote
14
down vote
accepted
Because template argument deduction is not that smart: it does not (by design) consider user-defined conversions. And int
-> Scalar<int>
is a user-defined conversion.
If you want to use TAD, you need to convert your argument at the caller site:
func(a, Scalar<int>{2});
or define a deduction guide1 for Scalar
and call f
:
func(a, Scalar{2}); // C++17 only
Alternatively, you can explicitly instantiate f
:
func<int>(a, 2);
1) The default deduction guide is sufficient: demo.
I've tested all three of your solutions and they will work as is; however if the OP declaredScalar()
asexplicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.
– Francis Cugler
Nov 9 at 14:47
add a comment |
up vote
2
down vote
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
template<typename Dtype>
void func(int a, Dtype b){
func(a, Scalar<Dtype>(std::move(b)));
}
template argument deduction is pattern matching, and it only matches the types or their base types exactly. It does no conversion.
Conversion is done later, at overload resolution & function call time.
Here, we add another overload that explicitly forwards to the one you want.
You probably wantb
to be aDtype&&
and usestd::forward
instead ofstd::move
for perfect forwarding.
– isanae
Nov 9 at 17:17
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',
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
});
}
});
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%2f53227713%2fwhy-does-the-implicit-type-conversion-not-work-in-template-deduction%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
up vote
14
down vote
accepted
Because template argument deduction is not that smart: it does not (by design) consider user-defined conversions. And int
-> Scalar<int>
is a user-defined conversion.
If you want to use TAD, you need to convert your argument at the caller site:
func(a, Scalar<int>{2});
or define a deduction guide1 for Scalar
and call f
:
func(a, Scalar{2}); // C++17 only
Alternatively, you can explicitly instantiate f
:
func<int>(a, 2);
1) The default deduction guide is sufficient: demo.
I've tested all three of your solutions and they will work as is; however if the OP declaredScalar()
asexplicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.
– Francis Cugler
Nov 9 at 14:47
add a comment |
up vote
14
down vote
accepted
Because template argument deduction is not that smart: it does not (by design) consider user-defined conversions. And int
-> Scalar<int>
is a user-defined conversion.
If you want to use TAD, you need to convert your argument at the caller site:
func(a, Scalar<int>{2});
or define a deduction guide1 for Scalar
and call f
:
func(a, Scalar{2}); // C++17 only
Alternatively, you can explicitly instantiate f
:
func<int>(a, 2);
1) The default deduction guide is sufficient: demo.
I've tested all three of your solutions and they will work as is; however if the OP declaredScalar()
asexplicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.
– Francis Cugler
Nov 9 at 14:47
add a comment |
up vote
14
down vote
accepted
up vote
14
down vote
accepted
Because template argument deduction is not that smart: it does not (by design) consider user-defined conversions. And int
-> Scalar<int>
is a user-defined conversion.
If you want to use TAD, you need to convert your argument at the caller site:
func(a, Scalar<int>{2});
or define a deduction guide1 for Scalar
and call f
:
func(a, Scalar{2}); // C++17 only
Alternatively, you can explicitly instantiate f
:
func<int>(a, 2);
1) The default deduction guide is sufficient: demo.
Because template argument deduction is not that smart: it does not (by design) consider user-defined conversions. And int
-> Scalar<int>
is a user-defined conversion.
If you want to use TAD, you need to convert your argument at the caller site:
func(a, Scalar<int>{2});
or define a deduction guide1 for Scalar
and call f
:
func(a, Scalar{2}); // C++17 only
Alternatively, you can explicitly instantiate f
:
func<int>(a, 2);
1) The default deduction guide is sufficient: demo.
edited Nov 9 at 14:54
answered Nov 9 at 14:38
YSC
20.3k34593
20.3k34593
I've tested all three of your solutions and they will work as is; however if the OP declaredScalar()
asexplicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.
– Francis Cugler
Nov 9 at 14:47
add a comment |
I've tested all three of your solutions and they will work as is; however if the OP declaredScalar()
asexplicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.
– Francis Cugler
Nov 9 at 14:47
I've tested all three of your solutions and they will work as is; however if the OP declared
Scalar()
as explicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.– Francis Cugler
Nov 9 at 14:47
I've tested all three of your solutions and they will work as is; however if the OP declared
Scalar()
as explicit
the third one will not compile. Not sure if this is something worth mentioning or not, but might be something important for the OP to be aware of.– Francis Cugler
Nov 9 at 14:47
add a comment |
up vote
2
down vote
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
template<typename Dtype>
void func(int a, Dtype b){
func(a, Scalar<Dtype>(std::move(b)));
}
template argument deduction is pattern matching, and it only matches the types or their base types exactly. It does no conversion.
Conversion is done later, at overload resolution & function call time.
Here, we add another overload that explicitly forwards to the one you want.
You probably wantb
to be aDtype&&
and usestd::forward
instead ofstd::move
for perfect forwarding.
– isanae
Nov 9 at 17:17
add a comment |
up vote
2
down vote
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
template<typename Dtype>
void func(int a, Dtype b){
func(a, Scalar<Dtype>(std::move(b)));
}
template argument deduction is pattern matching, and it only matches the types or their base types exactly. It does no conversion.
Conversion is done later, at overload resolution & function call time.
Here, we add another overload that explicitly forwards to the one you want.
You probably wantb
to be aDtype&&
and usestd::forward
instead ofstd::move
for perfect forwarding.
– isanae
Nov 9 at 17:17
add a comment |
up vote
2
down vote
up vote
2
down vote
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
template<typename Dtype>
void func(int a, Dtype b){
func(a, Scalar<Dtype>(std::move(b)));
}
template argument deduction is pattern matching, and it only matches the types or their base types exactly. It does no conversion.
Conversion is done later, at overload resolution & function call time.
Here, we add another overload that explicitly forwards to the one you want.
template<typename Dtype>
void func(int a, Scalar<Dtype> b){
cout << "ok" <<endl;
}
template<typename Dtype>
void func(int a, Dtype b){
func(a, Scalar<Dtype>(std::move(b)));
}
template argument deduction is pattern matching, and it only matches the types or their base types exactly. It does no conversion.
Conversion is done later, at overload resolution & function call time.
Here, we add another overload that explicitly forwards to the one you want.
answered Nov 9 at 15:21
Yakk - Adam Nevraumont
181k19188368
181k19188368
You probably wantb
to be aDtype&&
and usestd::forward
instead ofstd::move
for perfect forwarding.
– isanae
Nov 9 at 17:17
add a comment |
You probably wantb
to be aDtype&&
and usestd::forward
instead ofstd::move
for perfect forwarding.
– isanae
Nov 9 at 17:17
You probably want
b
to be a Dtype&&
and use std::forward
instead of std::move
for perfect forwarding.– isanae
Nov 9 at 17:17
You probably want
b
to be a Dtype&&
and use std::forward
instead of std::move
for perfect forwarding.– isanae
Nov 9 at 17:17
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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%2f53227713%2fwhy-does-the-implicit-type-conversion-not-work-in-template-deduction%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
4
Possible duplicate of C++ implicit type conversion with template
– jwismar
Nov 9 at 14:38