Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么可以';当模板参数用作另一个模板的模板参数时,是否可以推导模板参数?_C++_Templates_Parameters - Fatal编程技术网

C++ 为什么可以';当模板参数用作另一个模板的模板参数时,是否可以推导模板参数?

C++ 为什么可以';当模板参数用作另一个模板的模板参数时,是否可以推导模板参数?,c++,templates,parameters,C++,Templates,Parameters,这个代码有什么问题 #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[]) {

这个代码有什么问题

#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;
}
#包括
模板
结构TMap
{
typedef std::映射类型;
};
模板
T测试(typename TMap::Type&TMap_){return 0.0;}
int _tmain(int argc,_TCHAR*argv[]
{
TMap::类型TMap;
tmap[1.1]=5.2;
双d=test(tmap);//错误:无法推导T的模板参数
返回0;
}

这是不可推断的上下文。这就是编译器无法推导模板参数的原因

想象一下,如果您可能有专门的
TMap
,如下所示:

template <>
struct TMap<SomeType>
{
    typedef std::map <double, double> Type;
};
这使得情况更加糟糕。现在,您已完成以下操作:

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


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

编译器错误消息说的正是:in
TMap::Type
T
不能根据 标准这样做的动机可能是它不是 技术上可能实现:编译器必须 实例化所有可能的
TMap
,以查看是否有一个(和 只有一个)与您通过的类型匹配。还有一个 无限数量的
TMap

即使您有:

TMap<SomeType>::Type = std::map<double, double>. 
TMap::Type=std::map。
但在调用test(tmap)之前

TMap::类型TMap;
tmap[1.1]=5.2;
双d=试验(tmap);
您已经将其声明为

TMap<double>::Type tmap;
TMap::类型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.
模板
结构TMap/。。。
模板
结构tmap\u t:tmap::Type{};
模板
T检验(tmap\u T tmap)/。。。
tmap\u t tmap;/。。。
双d=测试(tmap);//编译得很好。
我看不出原始示例和我的示例之间有很大的区别。这里的实际问题似乎是C++对类型错误和类型声明的处理不同:


这是件好事吗?

回答得很好。这个问题让我反复犯错,我花了很长时间才明白为什么不可能推断出上下文。你的简短例子很好地说明了这一点。所以我必须写:double d=test(tmap)?如果可以的话,我可以给出+10的答案。与主题的复杂性相比,这是一个彻底而精确的答案。这本质上是一个反函数问题:给定一个输出值,你需要的是函数取该值的输入点。然而,函数通常是不可逆的,所以这个问题甚至不存在,除非你要求你的函数是可逆的。在模板场景中,相应的要求是所有模板都具有全局唯一的成员名称;一个C++不做的要求。@ SigFutt:不,不明显。请再读我的答案,再读一遍,关于模板特化。我想你在这里犯了一个错误——编译器“只”必须考虑所有现有专业席的传递闭包,并推断出最佳匹配。这是一个有限(但可能仍然非常大)数量的实例化。但除此之外,可能还有几场同样好的比赛(见纳瓦兹的例子)。在许多情况下,不会有任何现有的专业化。即使有,类型归纳也可以触发新的专门化。@James如果没有专门化,那么情况“很简单”:只需尝试在typedef上进行模式匹配即可推断模板参数。这在原则上应该是可行的。@Konrad:即使没有专业,情况也不容易。假设
std::map
的类型参数相同,或者取决于
TMap
的类型,这是不安全的。最糟糕的问题当然是模板元编程是图灵完全的。这反过来意味着,必要的模式匹配相当于解决暂停问题(即,编写
A::B
的专门化,以便
B
被类型定义为int,如果N表示暂停的算法)
TMap<double>::Type tmap;
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.