为什么SFINAE不适用于此?

时间:2009-10-22 12:00:40

标签: c++ sfinae

我在尝试使用Visual Studio 10(Beta 2)时正在编写一些简单的点代码,而且我已经按照这个代码开始我希望SFINAE启动,但似乎没有:

template<typename T>
struct point {
    T x, y;
    point(T x, T y) : x(x), y(y) {}
};

template<typename T, typename U>
struct op_div {
    typedef decltype(T() / U()) type;
};

template<typename T, typename U>
point<typename op_div<T, U>::type>
operator/(point<T> const& l, point<U> const& r) {
    return point<typename op_div<T, U>::type>(l.x / r.x, l.y / r.y);
}

template<typename T, typename U>
point<typename op_div<T, U>::type>
operator/(point<T> const& l, U const& r) {
    return point<typename op_div<T, U>::type>(l.x / r, l.y / r);
}

int main() {
    point<int>(0, 1) / point<float>(2, 3);
}

这会给error C2512: 'point<T>::point' : no appropriate default constructor available

鉴于它是测试版,我使用在线comeau编译器进行了快速的健全性检查,并且它同意相同的错误,因此看起来这种行为是正确的,但我看不出原因。

在这种情况下,一些解决方法是简单地内联decltype(T() / U()),给点类提供默认构造函数,或者在完整结果表达式上使用decltype,但是在尝试简化错误时我遇到了这个错误我得到了一个不需要默认构造函数*的op_div版本,所以我宁愿修复我对C ++的理解,而不是仅仅做有效的工作。

谢谢!


*:原文:

template<typename T, typename U>
struct op_div {
    static T t(); static U u();
    typedef decltype(t() / u()) type;
};

哪个提供error C2784: 'point<op_div<T,U>::type> operator /(const point<T> &,const U &)' : could not deduce template argument for 'const point<T> &' from 'int',以及point<T> / point<U>重载。

2 个答案:

答案 0 :(得分:2)

不是100%肯定。似乎编译器需要实例化两个重载以确定哪个更好,但在尝试使用T = intU = point<float>实例化另一个op_div时,这会导致SFINAE未涵盖的错误(错误不是op_div在这种情况下没有类型,但是无法确定该类型。)

如果第二种类型是一个点(boost::disable_if),您可以尝试禁用第二次重载。

此外,似乎有效的是推迟返回类型声明(取消op_div结构,但取决于编译器支持哪些C ++ 0x功能):

template<typename T, typename U>
auto
operator/(point<T> const& l, point<U> const& r) -> point<decltype(l.x / r.x)> {
    return {l.x / r.x, l.y / r.y};
}

template<typename T, typename U>
auto
operator/(point<T> const& l, U const& r) -> point<decltype(l.x / r)> {
    return {l.x / r, l.y / r};
}

答案 1 :(得分:-1)

我会说你的错误在这里:

template<typename T>
struct point {
    T x, y;
    point(T x, T y) : x(x), y(y) {}
};

将结构定义更改为:

template<typename T>
struct point<T> {
    T x, y;
    point(T x, T y) : x(x), y(y) {}
};

如果要使用泛型类型T,则需要在定义中指定它。