Why does the implicit type conversion not work in template deduction?











up vote
12
down vote

favorite
1












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);









share|improve this question




















  • 4




    Possible duplicate of C++ implicit type conversion with template
    – jwismar
    Nov 9 at 14:38















up vote
12
down vote

favorite
1












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);









share|improve this question




















  • 4




    Possible duplicate of C++ implicit type conversion with template
    – jwismar
    Nov 9 at 14:38













up vote
12
down vote

favorite
1









up vote
12
down vote

favorite
1






1





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);









share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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














  • 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












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.






share|improve this answer























  • 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




















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.






share|improve this answer





















  • 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











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%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.






share|improve this answer























  • 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

















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.






share|improve this answer























  • 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















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.






share|improve this answer














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.







share|improve this answer














share|improve this answer



share|improve this answer








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


















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














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.






share|improve this answer





















  • 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















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.






share|improve this answer





















  • 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













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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 9 at 15:21









Yakk - Adam Nevraumont

181k19188368




181k19188368












  • 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
















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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini