模板中的隐式转换和编译器强制

发布于 2024-10-17 17:47:50 字数 1562 浏览 2 评论 0原文

我有这个非常简单的包装模板:

template<class T>
struct wrapper {
    inline operator T () {
        return v;
    }

    inline wrapper(T v):v(v) { }

    T v;
};

尝试将它与任何非原始类型一起使用(例如)依赖于定义它的模板的比较运算符看起来不太有希望:

std::string t = "test";
assert(t == t);

typedef wrapper<std::string> string_wrapper;
assert(string_wrapper(t) == string_wrapper(t));

GCC 4.4.5 抱怨这个错误:

error: no match for ‘operator==’ in ‘wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t))))) == wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t)))))’

什么是有趣的问题是 GCC 对模板进行三重转换,然后无法使用为 std::string 定义的 operator ==

我不认为隐式强制转换是不可能的,因为如果我将 std::string 更改为 intdouble, bool< /code> 或任何原始的东西,GCC 将选择正确的运算符。

我不想为包装器结构定义 operator == ,因为该运算符只是一个示例,我需要 wrapper 来“感觉”就像真实类型一样运营商。

只是在转换中,GCC 误解了我的语法,如果我创建一个包装器并尝试将其与自身进行比较,GCC 会再次抱怨(尽管没有三重转换)它找不到匹配的 == 运算符:

typedef wrapper<std::string> string_wrapper;
string_wrapper tw(t);
assert(tw == tw);

error: no match for ‘operator==’ in ‘tw == tw’

Why can't GCC find and/or use当 wrapper 提供强制转换时,std::string 运算符 == std::string

I have this very simple wrapper template:

template<class T>
struct wrapper {
    inline operator T () {
        return v;
    }

    inline wrapper(T v):v(v) { }

    T v;
};

Trying to use it with any non-primitive type with (for example) comparison operator relying on the template having it defined doesn't look promising:

std::string t = "test";
assert(t == t);

typedef wrapper<std::string> string_wrapper;
assert(string_wrapper(t) == string_wrapper(t));

GCC 4.4.5 complains with this error:

error: no match for ‘operator==’ in ‘wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t))))) == wrapper<std::basic_string<char> >(std::basic_string<char>(((const std::basic_string<char>&)((const std::basic_string<char>*)(& t)))))’

What is interesting is that GCC triple-casts the template then fails to use operator == that was defined for std::string.

I don't think that implicit coercion is impossible, since if I change std::string to int or double, bool or anything primitive, GCC will choose the correct operator.

I do not want to define operator == for the wrapper struct, because that operator is just an example, and I need wrapper to 'feel' just like the real type regarding operators.

Just in cast GCC misunderstands my syntax, if I create a wrapper and try to compare it to itself, GCC complains again (though without triple casting) that it cannot find a matching == operator:

typedef wrapper<std::string> string_wrapper;
string_wrapper tw(t);
assert(tw == tw);

error: no match for ‘operator==’ in ‘tw == tw’

Why can't GCC find and/or use std::string operator == std::string when wrapper provides the cast?

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

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

发布评论

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

评论(3

相权↑美人 2024-10-24 17:47:50

该运算符 T 称为“转换运算符”或“转换函数”,而不是强制转换。 “转换”是隐式的;铸造是明确的。

编译器找不到 std::string 的运算符==,因为重载解析规则不允许发生这种情况。有关您真正想要做的事情的更多详细信息可能有助于提供解决方案。

That operator T is called a "conversion operator" or "conversion function" instead of a cast. "Conversions" are implicit; casting is explicit.

The compiler can't find the operator== for std::string because the overload resolution rules don't allow that to happen. More details about what you're really trying to do could help provide a solution.

独自唱情﹋歌 2024-10-24 17:47:50

显然这是 GCC 4.5 的一个错误。该代码是有效的,与 Fred Nurk 所说的不同。

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45383

Apparently this is a GCC 4.5 bug. The code is valid, unlike what Fred Nurk says.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45383

花之痕靓丽 2024-10-24 17:47:50

提问者用一些海湾合作委员会公关回答了自己,但这实际上并没有回答他的问题。

原因就像@Fred 描述的那样。减少它:

template<typename T>
struct A {
  operator T() { return T(); }
};

int main() {
  A<std::string>() == A<std::string>();
}

编译器能做什么?它可以对两个操作数调用operator std::string(),然后进行比较。但为什么它首先要执行该调用呢?它首先需要找到一个具有两个 std::string 类型参数的 operator==。让我们看看它的运算符是如何定义的

template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT,traits,Allocator>& lhs,
                const basic_string<charT,traits,Allocator>& rhs);

。这样我们就得到了它。它首先需要进行模板参数推导,并且 Aconst basic_string<> 不匹配的事实将使得这个 operator== 被忽略。您很幸运,无论如何使用 ADL 都能找到 operator== ,以便它首先进行参数推导(因为 std::string 是您类型的模板参数,它将通过 ADL 考虑命名空间 std 并找到此运算符)。

所以我们没有合适的 operator== 来调用,因此 GCC 可以拒绝你的代码,原因是 @Fred 简而言之。最后,试图让一个类表现得像另一种类型被认为是失败的。

The questioner has answered itself with some GCC PR, but which really does not answer his question.

The reason is like @Fred describes. Reducing it:

template<typename T>
struct A {
  operator T() { return T(); }
};

int main() {
  A<std::string>() == A<std::string>();
}

What can the compiler do? It could call operator std::string() on both operands and then do the comparison. But why should it do that call in the first place? It first needs to find an operator== that has two parameters of type std::string. Let's look at how its operator is defined

template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT,traits,Allocator>& lhs,
                const basic_string<charT,traits,Allocator>& rhs);

There we have it. It first needs to do template argument deduction, and the fact that A does not match const basic_string<> will make it so that this operator== is ignored. You are lucky that operator== is found anyway using ADL so that it does argument deduction in the first place (since std::string is a template argument of your type, it will consider namespace std by ADL and find this operator).

So we have no suitable operator== to call and therefor GCC is alright with rejecting your code for the reasons @Fred gave in a nutshell. In the end, trying to make a class behave like another type is deemed to failure.

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