3

I have this function definition in my code:

template < class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT> > std::basic_string<CharT, Traits, Allocator> bytes2string(const Bytes& bytes) { // do work ... } 

And when I try to call the function like this:

int main() { Bytes bytes{'H', 'e', 'l', 'l', 'o'}; std::string str = bytes2string(bytes); // error return 0; } 

I am met with the following error:

error: no matching function for call to 'bytes2string' note: candidate template ignored: couldn't infer template argument 'CharT' > std::basic_string<CharT, Traits, Allocator> bytes2string(const Bytes& bytes) 

I'm pretty sure it should work but alas, it doesn't. Also Bytes is just a std::vector<char> in case anyone wanted to know.

4
  • 2
    How do you expect the template parameters to be deduced? Commented Nov 13, 2017 at 21:51
  • Well std::string is really std::basic_string<char> so I would have expected the compiler to pick up on that. In this particular case CharT should get deduced as char Commented Nov 13, 2017 at 21:56
  • Without any source for CharT in the arguments, there's no way for it to figure out what the template parameters should be. You're plainly expecting to assign the result to a std::string, so you want CharT to a basic char, but that doesn't factor into the parameter deduction. Commented Nov 13, 2017 at 21:56
  • in C++ the return type doesn't participate in overload resolution. Commented Nov 13, 2017 at 21:58

2 Answers 2

4

Look closely at your signature:

template < class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT> > std::basic_string<CharT, Traits, Allocator> bytes2string(const Bytes& bytes); 

There's nothing that allows CharT to be deduced - it needs to be explicitly supplied by the user.


std::string str = bytes2string(bytes); 

Unfortunately C++ doesn't have Hindley-Milner type inference - it is not possible to deduce template parameters of a return type in this way. Function template parameters can only be deduced via arguments passed to the function.

If you change your signature to:

template < class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT> > void bytes2string(std::basic_string<CharT, Traits, Allocator>& out, const Bytes& bytes); 

And invoke:

std::string str; bytes2string(str, bytes); 

Your template parameters will be deduced.

live example on wandbox

Sign up to request clarification or add additional context in comments.

1 Comment

Damn. I was under the impression it supported such inferences. Thanks
2

If the function is supposed to return std::string, then write it that way:

std::string bytes2string(const Bytes& bytes); 

If it's supposed to be able to produce arbitrary instantiations of std::basic_string then you need to supply the appropriate template arguments. Often that's done by passing in a string of the appropriate type. That doesn't seem appropriate here, since there is no obvious use for passing in a string other than to provide template arguments.

The alternative is to name the appropriate types at the point of the call:

std::string str = bytes2string<char>(bytes); 

1 Comment

Yep, I guessed as much but I really wanted the type deduction. Thanks

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.