潜在的g ++模板错误?

时间:2011-01-13 07:27:33

标签: c++ templates g++

我遇到了一些我认为应编译的代码,但却没有。所以我希望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。

3 个答案:

答案 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推断为什么? XY

在这种特殊情况下,一个解决方案是将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推导出模板参数==Tint还是double?没有办法说。

为了避免这些歧义,这种情况被称为非推断的上下文。从嵌套类型中推导出封闭类模板参数是非推断上下文的一个示例。