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

19.2k34590




19.2k34590










asked Nov 9 at 14:33









Yulong Ao

453617




453617







  • 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
13
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, Scalar2); // 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
13
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, Scalar2); // 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
13
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, Scalar2); // 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
13
down vote



accepted







up vote
13
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, Scalar2); // 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, Scalar2); // 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

19.2k34590




19.2k34590











  • 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

177k19182362




177k19182362











  • 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















































 


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







Popular posts from this blog

Use pre created SQLite database for Android project in kotlin

Darth Vader #20

Ondo