Martin
Martin

Reputation: 9369

Type deduction/substitution failure

Consider the following example.

#include <string>


template<class CharT, class Traits = std::char_traits<CharT >, class Allocator = std::allocator<CharT >>
void f(const std::basic_string<CharT, Traits, Allocator>& s) {
}

int main() {
     f("Hello World!");
}

When compiling it, I get

mismatched types ‘const std::basic_string<_CharT, _Traits, _Alloc>’ and ‘const char []’

Why cannot the compiler deduct "CharT" and do the conversion to the appropriate basic_string<>? I'd like to have only one signature for f() valid for any argument type for which a conversion to a basic_string<> exists, is there any solution for this problem?

Upvotes: 2

Views: 1971

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

What you ask would require the compiler iterate over every basic_string<T> until it determined that there was exactly one T that matched. Alternatively, it could invert the possibly Turing complete process to figure out what the template argument is. template argument deduction like that is pattern matching: it takes the arguments, and matches it against your pattern, and deduces the types simply. If you want more, you need to tell it how to invert the mapping from CharT to basic_string<CharT,A> constructors. C++1y makes it a touch easier with concepts lite, but the kind of machinery you want still will not be there.

By far the easiest solution is to have two overloads for char and wchar_t basic_strings (actual functions, not templates), and then have them call a template generic function like what you wrote passing in the CharT explicitly.

Fancier would involve code that actually did the above inversion, where you might have it work from an acceptable set of strings, and check which the arguments can be constructed from, assert that there is only one option, and deduce CharT that way. While fun, I doubt this is worth it.

Upvotes: 1

Manu343726
Manu343726

Reputation: 14174

You are passing a raw string to your function, which is not a std::string, is a character array, a const char [].
Even if std::string has a constructor which gets a char array, implicit type conversions are not applied during template argumment deduction (Exactly the problem you have). See this thread for more information about the topic.

There are two possible solutions:

  1. Pass a std::string instead of a raw string to your function:

    f( std::string( "hello" ) );
    
  2. Write an overload of your function which works with raw strings:

    template<typename CHAR_T , std::size_t LENGHT>
    void f( const CHAR_T (&string)[LENGTH] )
    {
        f( std::string( string ) ); //Just wrap the call to not duplicate code.
    }
    

Upvotes: 6

Yabada
Yabada

Reputation: 1758

This should do the trick.

You're specifying a char array to your function witch is supposed to get std::string. You need to use a constructor to convert these.

#include <string>


template<class CharT, class Traits = std::char_traits<CharT >, class Allocator = std::allocator<CharT >>
void f(const std::basic_string<CharT, Traits, Allocator>& s) {
}

int main() {
     std::string str("Hello World!");
     f(str);
}

Upvotes: 0

Related Questions