Why can't the template argument be deduced when it is used as template parameter to another template?
What is wrong in this code?
#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;
do开发者_如何学JAVAuble d = test(tmap); //Error: could not deduce template argument for T
return 0;
}
That is non-deducible context. That is why the template argument cannot be deduced by the compiler.
Just imagine if you might have specialized TMap
as follows:
template <>
struct TMap<SomeType>
{
typedef std::map <double, double> Type;
};
How would the compiler deduce the type SomeType
, given that TMap<SomeType>::Type
is std::map<double, double>
? It cannot. It's not guaranteed that the type which you use in std::map
is also the type in TMap
. The compiler cannot make this dangerous assumption. There may not any relation between the type arguments, whatsoever.
Also, you might have another specialization of TMap
defined as:
template <>
struct TMap<OtherType>
{
typedef std::map <double, double> Type;
};
This makes the situation even worse. Now you've the following:
TMap<SomeType>::Type
=std::map<double, double>
.TMap<OtherType>::Type
=std::map<double, double>
.
Now ask yourself: given TMap<T>::Type
is std::map<double, double>
, how would the compiler know whether T
is SomeType
or OtherType
? It cannot even know how many such choices it has, neither can it know the choices themselves...
I'm just asking you for the sake of thought-experiment (assuming it can know the complete set of choices).
Exactly what the compiler error message says: in
TMap<T>::Type
, T
is not deduceable according to the
standard. The motivation for this is probably that it isn't
technically possible to implement: the compiler would have to
instantiate all possible TMap<T>
in order to see if one (and
only one) matched the type you passed. And there is an
infinite number of TMap<T>
.
Even you have:
TMap<SomeType>::Type = std::map<double, double>.
But before you call test(tmap)
TMap<double>::Type tmap;
tmap[1.1] = 5.2;
double d = test(tmap);
You already have it declared as
TMap<double>::Type tmap;
why this information can not be utilized. #typedef is not just simple string replacement.
I don't think "we can't do this" argument is correct. If we slightly modify this example, the compiler is happily deducing arguments for us.
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.
I don't see a huge difference between the original example and mine. The real issue here seems that C++ treats typedefs and type declarations differently
Is this a good thing?
精彩评论