为什么 SFINAE 不适用于此?

发布于 2024-08-08 19:00:13 字数 1526 浏览 6 评论 0 原文

我在尝试 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);
}

这给出了错误 C2512:' point::point' : 没有合适的默认构造函数可用

鉴于它是测试版,我使用在线 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;
};

给出错误 C2784:'point::type>;运算符 /(const point &,const U &)' :无法推导出 'const point; 的模板参数&'来自 'int',也适用于 point /点过载。

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);
}

This gives error C2512: 'point<T>::point' : no appropriate default constructor available

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.

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.

Thanks!


*: the original:

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁我热情 2024-08-15 19:00:13

不是100%确定。编译器似乎需要实例化两个重载来确定哪个更好,但是在尝试使用 T = intU = point 实例化另一个 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};
}

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).

You could try to disable the second overload if the second type is a point (boost::disable_if).

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};
}
叹梦 2024-08-15 19:00:13

我想说你的错误在这里:

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,你需要在定义中指定它。

I would say your error is in here:

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

Change your struct definition to this:

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

If you want to use a generic type T, you need to specify it in the definition.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文