Почему нельзя получить аргумент шаблона, если он используется в качестве параметра шаблона для другого шаблона? - PullRequest
51 голосов
/ 19 мая 2011

Что не так в этом коде?

#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 ]

82 голосов
/ 19 мая 2011

Это не выводимый контекст.Вот почему аргумент шаблона не может быть выведен компилятором.

Только представьте, если бы вы могли специализировать TMap следующим образом:

template <>
struct TMap<SomeType>
{
    typedef std::map <double, double> Type;
};

Как компилятор может определить тип SomeType, учитывая, что TMap<SomeType>::Type равно std::map<double, double>?Это не может. не гарантирует, что тип , который вы используете в std::map, также тип в TMap.Компилятор не может сделать это опасное предположение.Между аргументами type может не быть никакой связи.

Кроме того, у вас может быть другая специализация 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?Он даже не может знать , сколько таких вариантов у него есть, и при этом он не может знать вариантов самих себя ...

Я просто прошу вас ради размышлений-эксперимент (при условии, что он может знать полный набор вариантов ).

4 голосов
/ 19 мая 2011

Именно то, что говорит сообщение об ошибке компилятора: в TMap<T>::Type, T не вычитается в соответствии с стандарт. Мотивация для этого, вероятно, заключается в том, что это не технически возможно реализовать: компилятор должен создать все возможные TMap<T>, чтобы увидеть, если один (и только один) соответствует типу, который вы передали. И есть бесконечное число TMap<T>.

2 голосов
/ 29 декабря 2014

Даже у вас есть:

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 - это не просто замена строк.

0 голосов
/ 05 августа 2017

Я не думаю, что аргумент "мы не можем сделать это" является правильным. Если мы немного изменим этот пример, компилятор с радостью выведет для нас аргументы.

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 ++ по-разному относится к определениям типов и объявлениям типов

Это хорошо?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...