This is a FAQ, yet I could not find a satisfying answer. In my project we support std::string
and now have to also support wide strings. So we want to move to basic_string
, but then, things stop working nicely and parameters need to be spelled out explicitly:
#include <string>
template <typename CharT, typename Traits, typename Allocator>
void
foo(const std::basic_string<CharT, Traits, Allocator>&)
{}
template void foo(const std::string&);
// template void
// foo<char, std::char_traits<char>, std::allocator<char>>(const std::string&);
void bar(const std::string& s)
{}
int main()
{
bar("abc");
foo<char, std::char_traits<char>, std::allocator<char>>("def");
foo("def");
}
OK, it fails for the well-known reason:
clang++-mp-3.5 -Wall -std=c++11 foo.cc
foo.cc:20:3: error: no matching function for call to 'foo'
foo("def");
^~~
foo.cc:5:1: note: candidate template ignored: could not match
'basic_string<type-parameter-0-0, type-parameter-0-1, type-parameter-0-2>'
against 'char const[4]'
foo(const std::basic_string<CharT, Traits, Allocator>&)
^
What I don't get it why does it work for bar
? Why doesn't the explicit instantiation of foo
for char
(either with explicit template parameters or with deduction) suffice to work around this problem?
It seems that it means that instead of using templates and basic_string
in the exposed API, we will have to use it as an implementation detail, but expose the user with overloads for std::string
, std::wstring
, etc. which is a shame.
Thanks!
For bar("abc")
there is an implicit conversion from char const[4]
to std::string
. foo
differs from bar
in that it's not actually a function but a function template. Its template arguments need to be known in order to build the correct function.
The first call to foo
explicitly provides the template arguments, so it builds a function that looks like this:
void foo(const std::basic_string<char, std::char_traits<char>, std::allocator<char>>&);
The implicit conversion kicks in and everything is fine.
The third call does not provide the template arguments, so the compiler has to figure out the type of CharT
, Traits
and Allocator
from the type char const[4]
. This type doesn't carry that information with it, so deduction fails and overload resolution cannot find the correct function.