Я написал небольшой код:
#include<type_traits>
using namespace std;
template<typename T>
struct M{
/*explicit*/ M(const T*) {}
};
template<typename T>
M<T> f(const M<T>&) {return M<T>();}
int main() {
M<char> s1 = f<char>("Hello"); // OK
M<char> s2 = f("Hello"); // error
M<char> s3 = f(decay<char*>("Hello")); // error
return 0;
}
Ну первое s1
успешно компилируется, хотя если я поменяю M::M
в явном виде, это также не удастся. Но s2
а также s3
не скомпилировать, даже когда я использую decay<char*>
на s3
,
Разница в том, указывал ли я тип аргумента инициализации шаблона для f
или нет. Почему s2
а также s3
не скомпилировать, какие-либо принципы, стоящие за этим в стандарте C ++?
Если я изменю основную функцию следующим образом:
int main()
{
M<char> s1=f<char>("Hello");//OK
const char* p="hello";
M<char> s2=f(p);//error
M<char> s3=f(decay<const char*>("Hello"));//error
return 0;
}
Это все еще не удается.
Зачем?
Спасибо за любую помощь.
Так как вычет аргумента типа шаблона не учитывает неявные преобразования.
Вывод типа не учитывает неявные преобразования (кроме корректировок типа, перечисленных выше): это работа по разрешению перегрузки, которая происходит позже.
Во втором случае компилятор не может соответствовать M<T>
с const char [6]
, шаблон функции просто игнорируется перед разрешением перегрузки.
3-й случай терпит неудачу, потому что "Hello"
(Т.е. const char [6]
) не может быть преобразован в decay<char *>
, Вы могли бы иметь в виду typename decay<char*>::type
, но он все равно не скомпилируется по той же причине, что и во втором случае.
Других решений пока нет …