Почему аргумент шаблона не может быть выведен, когда он используется в качестве параметра шаблона для другого шаблона?
Что не так в этом коде?
#include <map>
template<typename T>
struct TMap
{
typedef std::map<T, T> Type;
};
template<typename T>
T test(typename TMap <T>::Type &tmap_) { return 0.0; }
int _tmain(int argc, _TCHAR* argv[])
{
TMap<double>::Type tmap;
tmap[1.1] = 5.2;
double d = test(tmap); //Error: could not deduce template argument for T
return 0;
}
4 ответа
Это не выводимый контекст. Вот почему аргумент шаблона не может быть выведен компилятором.
Представьте себе, если бы вы могли специализироваться TMap
следующее:
template <>
struct TMap<SomeType>
{
typedef std::map <double, double> Type;
};
Как бы компилятор выводил тип SomeType
, При условии TMap<SomeType>::Type
является std::map<double, double>
? Это не может. Не гарантируется, что тип, который вы используете в std::map
также тип в TMap
, Компилятор не может сделать это опасное предположение. Между аргументами типа не может быть никакой связи.
Кроме того, у вас может быть другая специализация TMap
определяется как:
template <>
struct TMap<OtherType>
{
typedef std::map <double, double> Type;
};
Это делает ситуацию еще хуже. Теперь у вас есть следующее:
TMap<SomeType>::Type
знак равноstd::map<double, double>
,TMap<OtherType>::Type
знак равноstd::map<double, double>
,
Теперь спросите себя: дано TMap<T>::Type
является std::map<double, double>
как бы компилятор узнал T
является SomeType
или же OtherType
? Он даже не может знать, сколько таких вариантов у него есть, и при этом он не может знать самих выборов...
Я просто прошу вас ради мысленного эксперимента (при условии, что он может знать полный набор вариантов).
Именно то, что говорит сообщение об ошибке компилятора: вTMap<T>::Type
, T
не вычитается в соответствии со стандартом. Мотивация для этого, вероятно, заключается в том, что это технически невозможно реализовать: компилятору придется создавать все возможные варианты TMap<T>
чтобы увидеть, соответствует ли один (и только один) типу, который вы передали. И существует бесконечное количество TMap<T>
,
Даже у вас есть:
TMap<SomeType>::Type = std::map<double, double>.
Но прежде чем вызвать test(tmap)
TMap<double>::Type tmap;
tmap[1.1] = 5.2;
double d = test(tmap);
Вы уже объявили это
TMap<double>::Type tmap;
почему эта информация не может быть использована. #typedef - это не просто замена строк.
Я не думаю, что аргумент "мы не можем сделать это" является правильным. Если мы немного изменим этот пример, компилятор с удовольствием выведет для нас аргументы.
template<typename T>
struct TMap //...
template <class T>
struct tmap_t : TMap<T>::Type {};
template<typename T>
T test(tmap_t<T> tmap) // ...
tmap_t<double> tmap; // ...
double d = test(tmap); // compiles just fine.
Я не вижу большой разницы между оригинальным примером и моим. Настоящая проблема здесь заключается в том, что C++ по-разному относится к определениям типов и объявлениям типов.
Это хорошо?