Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

T = char can't be deduced for std::basic_string<T> foo = "foo"?

Tags:

c++

Question: In the code below, template argument type deduction seems to fail for the first sample, but not for the second sample. I don't understand why the first sample fails to deduce T = char. I would think that T can be deduced when converting from "foo" to std::bacis_string<T>, but even if that didn't work, I provide the second function argument which, I would think, would clearly constrain T to char. Why does it fail?

Does not work:

#include <iostream>
#include <string>

template <typename T>
void print(const std::basic_string<T>& a, const std::basic_string<T>& b)
{
    std::cout << a << b << std::endl;
}

int main()
{
    std::string bar = "bar";
    print("foo", bar);
}

Error:

string.cpp:14:5: error: no matching function for call to 'print'
    print("foo", bar);
    ^~~~~
string.cpp:6:6: note: candidate template ignored: could not match
      'basic_string<type-parameter-0-0, char_traits<type-parameter-0-0>,
      allocator<type-parameter-0-0> >' against 'char const[4]'
void print(const std::basic_string<T>& a, const std::basic_string<T>& b)
     ^
1 error generated.

Works:

#include <iostream>
#include <string>

template <typename T>
void print(const std::basic_string<T>& a, const std::basic_string<T>& b)
{
    std::cout << a << b << std::endl;
}

int main()
{
    std::string foo = "foo";
    std::string bar = "bar";
    print(foo, bar);
}
like image 842
Cornstalks Avatar asked Apr 10 '14 06:04

Cornstalks


2 Answers

The problem is a conversion is required here. To deduce T, the compiler would have to inspect all possible instantiations of std::basic_string and see which of them can be constructed from a const char* (or actually const char (&)[4]). That's of course not possible, as there's infinitely many of them. The reason why it has to inspect all and cannot just scan the primary template definition for constructors taking const char* or const char(&)[4] is that for some T, std::basic_string<T> could be partially or completely specialised, and the members of those specialisations have no relationship to the members of the primary template.

like image 84
Angew is no longer proud of SO Avatar answered Nov 02 '22 00:11

Angew is no longer proud of SO


Here's the short version of an answer.

The compiler has char const[] and is looking to convert that to std::basic_string<T>. How does it work out what T is? You know that you want to match T = char but the compiler does not know that.

It could look for a constructor basic_string<T>(char const *), for example. Even if that exists, it still does not say what T should be.

The compiler doesn't iterate over all possible typenames it knows about and attempt basic_string<T> for each one, and then see if there is a matching constructor.

Similar example:

template<typename T>
struct Foo
{
    Foo(T t) {}
};

int main()
{
    Foo(0);    // error, can't deduce Foo<int>
}
like image 23
M.M Avatar answered Nov 02 '22 00:11

M.M