T = char не может быть выведено для std:: basic_string <T> foo = "foo"?

Вопрос: В приведенном ниже коде вывод типа аргумента шаблона кажется неудачным для первого образца, но не для второго образца. Я не понимаю, почему первый образец не выводит T = char. Я бы подумал, что T может быть выведен при преобразовании из "foo" в std::bacis_string<T>, но даже если это не сработало, я предоставляю второй аргумент функции, который, я думаю, явно сдерживал бы T до char. Почему это не удается?

Не работает:

#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);
}

Ошибка:

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.

Работы:

#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);
}

Ответ 1

Проблема в том, что здесь требуется преобразование. Чтобы вывести T, компилятор должен был бы проверить все возможные экземпляры std::basic_string и посмотреть, какие из них можно построить из const char* (или фактически const char (&)[4]). Это, конечно, невозможно, так как их бесконечно много. Причина, по которой он должен проверять все и не может просто проверять определение первичного шаблона для конструкторов, принимающих const char* или const char(&)[4], - это то, что для некоторых T, std::basic_string<T> может быть частично или полностью специализированным, а члены этих специализаций не имеют отношения к членам первичного шаблона.

Ответ 2

Вот короткая версия ответа.

У компилятора есть char const[] и он хочет преобразовать его в std::basic_string<T>. Как это работает, что T? Вы знаете, что хотите сопоставить T = char, но компилятор этого не знает.

Он мог бы искать конструктор basic_string<T>(char const *), например. Даже если это существует, он все еще не говорит, что должно быть T.

Компилятор не перебирает все возможные имена, о которых он знает, и пытается выполнить basic_string<T> для каждого из них, а затем посмотреть, есть ли соответствующий конструктор.

Аналогичный пример:

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

int main()
{
    Foo(0);    // error, can't deduce Foo<int>
}