Why can't the template argument be deduced when it is used as template parameter to another template?

前端 未结 4 1978
无人共我
无人共我 2020-11-22 09:02

What is wrong in this code?

#include 

template
struct TMap
{
    typedef std::map Type;
};

template

        
相关标签:
4条回答
  • 2020-11-22 09:50

    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>.

    0 讨论(0)
  • 2020-11-22 09:53

    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?

    0 讨论(0)
  • 2020-11-22 09:55

    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).

    0 讨论(0)
  • 2020-11-22 10:04

    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.

    0 讨论(0)
提交回复
热议问题