我遇到了一些我认为应编译的代码,但却没有。所以我希望SO的一些当地标准专家可以提供帮助: - )。
我基本上有一些类似于此的代码:
#include <iostream>
template <class T = int>
class A {
public:
class U {
};
public:
U f() const { return U(); }
};
// test either the work around or the code I want...
#ifndef USE_FIX
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
#else
typedef A<int> AI;
bool operator==(const AI::U &x, int y) {
return true;
}
#endif
int main() {
A<int> a;
std::cout << (a.f() == 1) << std::endl;
}
所以,来描述这里发生了什么。我有一个类模板(A
),它有一个内部类(U
)和至少一个可以返回该内部类(f()
)实例的成员函数。
然后我尝试创建一个operator==
函数,将此内部类型与其他类型(在本例中为int
进行比较,但似乎并不重要。)
当USE_FIX
未定义时,我收到以下错误:
test.cc: In function 'int main()':
test.cc:27:25: error: no match for 'operator==' in 'a.A<T>::f [with T = int]() == 1'
这看起来很奇怪,因为我很清楚(我认为)定义了一个模板operator==
,它应该涵盖这个,事实上如果我只是为编译器做一些工作(启用USE_FIX),那么我没有更长时间出错。不幸的是,“修复”一般不起作用,仅用于模板的特定实例化。
这应该按照我的预期运作吗?或者这是不允许的?
顺便说一句:如果重要的话我正在使用gcc 4.5.2。答案 0 :(得分:15)
const typename A<T>::U &x
的问题是U
是一个依赖类型,并且编译器不能从参数中推导出T
(这是非受限上下文之一)。
A
的两个专业:
class X { };
class Y { };
class Z { };
template <> class A<X> {
public:
typedef Z U;
};
template <> class A<Y> {
public:
typedef Z U;
};
如果您再打电话:
Z a;
a == 1;
编译器应该将T
推断为什么? X
? Y
?
在这种特殊情况下,一个解决方案是将operator==
声明为类模板中的非模板朋友:
template <class T = int>
class A {
public:
class U {
};
friend bool operator==(const U& x, int y) {
return true;
}
public:
U f() const { return U(); }
};
答案 1 :(得分:11)
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
使用此模板,不允许(或有时可能)从T
的类型中推导出模板参数x
。这就是所谓的不可推导的背景。 (例如,某人可以将A
专门用于其他参数,例如double
并使A<double>::U
成为A<int>::U
的typedef。)
没有解决方法,您必须明确指定operator==
造成难看语法的模板参数。
答案 2 :(得分:4)
不允许出于相当明显的原因。一般情况下,编译器无法从调用operator ==
中推断出模板参数。显然,您假设嵌套类型U
唯一地定义了封闭式A
专门化。事实并非如此,下面的示例可以通过A
template <> class A<int> {
public:
class U {};
};
template <> class A<double> {
public:
typedef A<int>::U U;
};
在这种情况下,如果使用类型为==
的参数调用模板化运算符A<int>::U
,则编译器无法为模板化运算符T
推导出模板参数==
。 T
应int
还是double
?没有办法说。
为了避免这些歧义,这种情况被称为非推断的上下文。从嵌套类型中推导出封闭类模板参数是非推断上下文的一个示例。