模板中的隐式转换和编译器强制
我有这个非常简单的包装模板:
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
更改为 int
或 double
, 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
该运算符 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.
显然这是 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
提问者用一些海湾合作委员会公关回答了自己,但这实际上并没有回答他的问题。
原因就像@Fred 描述的那样。减少它:
编译器能做什么?它可以对两个操作数调用
operator std::string()
,然后进行比较。但为什么它首先要执行该调用呢?它首先需要找到一个具有两个std::string
类型参数的operator==
。让我们看看它的运算符是如何定义的。这样我们就得到了它。它首先需要进行模板参数推导,并且
A
与const 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:
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 anoperator==
that has two parameters of typestd::string
. Let's look at how its operator is definedThere we have it. It first needs to do template argument deduction, and the fact that
A
does not matchconst basic_string<>
will make it so that thisoperator==
is ignored. You are lucky thatoperator==
is found anyway using ADL so that it does argument deduction in the first place (sincestd::string
is a template argument of your type, it will consider namespacestd
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.