当模板参数被用作另一个模板的模板参数时,为什么不能推断模板参数呢?

时间:2022-10-13 16:29:26

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;
    double d = test(tmap); //Error: could not deduce template argument for T
    return 0;
}

4 个解决方案

#1


79  

That is non-deducible context. That is why the template argument cannot be deduced by the compiler.

这是non-deducible上下文。这就是为什么编译器不能推导模板参数的原因。

Just imagine if you might have specialized TMap as follows:

想象一下,如果你有如下专门的TMap:

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.

如果TMap :: type是std:::map ,编译器如何推断类型为SomeType ?它不能。不能保证在std:::map中使用的类型也是TMap中的类型。编译器不能做出这种危险的假设。类型参数之间可能没有任何关系。 ,>

Also, you might have another specialization of TMap defined as:

此外,您可能还有另一个TMap的专门化定义为:

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 < SomeType >::Type = std:: <双,双> 地图。
  • TMap<OtherType>::Type = std::map<double, double>.
  • TMap < OtherType >::Type = std:: <双,双> 地图。

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

现在问自己:给定TMap ::类型是std::map ,编译器如何知道T是SomeType还是OtherType?它甚至不知道自己有多少这样的选择,也不知道自己的选择…… ,>

I'm just asking you for the sake of thought-experiment (assuming it can know the complete set of choices).

我只是为了思想实验而问你(假设它能知道完整的选择集)。

#2


4  

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

确切地说,编译器错误消息说:在TMap ::Type中,T根据标准是不可抵扣的。这样做的原因可能是技术上不可能实现:编译器必须实例化所有可能的TMap ,以查看是否有一个(而且只有一个)匹配您传递的类型。TMap 的数量是无限的。

#3


2  

Even you have:

甚至你有:

TMap<SomeType>::Type = std::map<double, double>. 

But before you call test(tmap)

但在调用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.

为什么这些信息不能被利用。#typedef不仅仅是简单的字符串替换。

#4


0  

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

我不觉得原来的例子和我的有很大的不同。这里的真正问题似乎是c++对typedef和类型声明的处理不同

Is this a good thing?

这是好事吗?

#1


79  

That is non-deducible context. That is why the template argument cannot be deduced by the compiler.

这是non-deducible上下文。这就是为什么编译器不能推导模板参数的原因。

Just imagine if you might have specialized TMap as follows:

想象一下,如果你有如下专门的TMap:

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.

如果TMap :: type是std:::map ,编译器如何推断类型为SomeType ?它不能。不能保证在std:::map中使用的类型也是TMap中的类型。编译器不能做出这种危险的假设。类型参数之间可能没有任何关系。 ,>

Also, you might have another specialization of TMap defined as:

此外,您可能还有另一个TMap的专门化定义为:

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 < SomeType >::Type = std:: <双,双> 地图。
  • TMap<OtherType>::Type = std::map<double, double>.
  • TMap < OtherType >::Type = std:: <双,双> 地图。

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

现在问自己:给定TMap ::类型是std::map ,编译器如何知道T是SomeType还是OtherType?它甚至不知道自己有多少这样的选择,也不知道自己的选择…… ,>

I'm just asking you for the sake of thought-experiment (assuming it can know the complete set of choices).

我只是为了思想实验而问你(假设它能知道完整的选择集)。

#2


4  

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

确切地说,编译器错误消息说:在TMap ::Type中,T根据标准是不可抵扣的。这样做的原因可能是技术上不可能实现:编译器必须实例化所有可能的TMap ,以查看是否有一个(而且只有一个)匹配您传递的类型。TMap 的数量是无限的。

#3


2  

Even you have:

甚至你有:

TMap<SomeType>::Type = std::map<double, double>. 

But before you call test(tmap)

但在调用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.

为什么这些信息不能被利用。#typedef不仅仅是简单的字符串替换。

#4


0  

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

我不觉得原来的例子和我的有很大的不同。这里的真正问题似乎是c++对typedef和类型声明的处理不同

Is this a good thing?

这是好事吗?