为什么 SFINAE 不适用于此? [英] Why does SFINAE not apply to this?
问题描述
我在尝试 Visual Studio 10 (Beta 2) 时正在编写一些简单的点代码,并且我已经在我希望 SFINAE 启动的地方找到了这段代码,但似乎没有:
I'm writing some simple point code while trying out Visual Studio 10 (Beta 2), and I've hit this code where I would expect SFINAE to kick in, but it seems not to:
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' : 没有合适的默认构造函数可用
鉴于它是一个测试版,我用在线的 Comeau 编译器做了一个快速的健全性检查,它同意一个相同的错误,所以这种行为似乎是正确的,但我不明白为什么.
Given that it is a beta, I did a quick sanity check with the online comeau compiler, and it agrees with an identical error, so it seems this behavior is correct, but I can't see why.
在这种情况下,一些解决方法是简单地内联 decltype(T()/U())
,给点类一个默认构造函数,或者在完整的结果表达式上使用 decltype,但是我在尝试简化不需要默认构造函数 * 的 op_div 版本时遇到的错误时遇到了这个错误,所以我宁愿修正我对 C++ 的理解,而不是只做有效的事情.
In this case some workarounds are to simply inline the decltype(T() / U())
, to give the point class a default constructor, or to use decltype on the full result expression, but I got this error while trying to simplify an error I was getting with a version of op_div that did not require a default constructor*, so I would rather fix my understanding of C++ rather than to just do what works.
谢谢!
*:原文:
template<typename T, typename U>
struct op_div {
static T t(); static U u();
typedef decltype(t() / u()) type;
};
这会导致 错误 C2784:'point
,也用于point<T>/point
重载.
Which gives 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'
, and also for the point<T> / point<U>
overload.
推荐答案
不是 100% 确定.似乎编译器需要实例化两个重载以确定哪个更好,但是在尝试使用 T = int
和 U = point
实例化另一个 op_div 时,这会导致 SFINAE 未涵盖的错误(在这种情况下,错误不是 op_div 没有类型,而是无法确定该类型).
Not 100% sure. It appears that the compiler needs to instantiate both overloads to determine which is better, but while trying to instantiate the other op_div with T = int
and U = point<float>
, this leads to an error that is not covered by SFINAE (the error is not that op_div doesn't have type in this case, but that type cannot be determined).
如果第二种类型是点 (boost::disable_if
),您可以尝试禁用第二个重载.
You could try to disable the second overload if the second type is a point (boost::disable_if
).
此外,似乎可行的是推迟返回类型声明(取消 op_div 结构,但取决于您的编译器支持哪些 C++0x 功能):
Also, what seems to work is postponed return type declaration (doing away with the op_div struct, but depending on which C++0x features are supported by your compiler):
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};
}
这篇关于为什么 SFINAE 不适用于此?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!