gpt4 book ai didi

c++ - 运算符重载、名称解析和命名空间

转载 作者:太空狗 更新时间:2023-10-29 21:15:14 25 4
gpt4 key购买 nike

我想阐明涉及 ADL、 namespace 和运算符重载的令人费解的情况。

让 Foo 成为一个库,它在自己的命名空间中定义一个类 (Deriv),以及一个返回另一个类的模板化 operator *

namespace Foo {
class Deriv {};
class Another {};

template <typename T>
Another operator* ( T x, const Deriv& d ) { return Another();}
}

现在我在自己的库 Bar 中使用 Foo 的类,它定义了另一个 operator *,这次只针对 float

namespace Bar {
typedef Foo::Deriv MyDeriv;
MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}

我观察到编译器行为的差异取决于是否在 namespace Bar 内。

此函数 (Bar::f1) 使用 operator * 的第二个版本进行编译:

namespace Bar {
void f1() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a;
}
}

而命名空间 Bar (f2()) 之外的相同函数无法编译,因为编译器仅尝试使用 Foo::operator* 而无法猜测它必须使用 Bar::operator*

void f2() {
Bar::MyDeriv a;
Bar::MyDeriv b = 3.f * a; // Error : cannot convert Foo:Another to Bar::Myderiv
}

您可以在此处查看代码:http://ideone.com/pkPeOY

现在,如果 Foo::operator* 没有被模板化并定义为 Foo::operator*(float, const Deriv& d); 那么两者 函数无法编译并出现相同的错误(不明确的运算符重载),如下所示:http://ideone.com/wi1EWS

所以,面对这种情况,这就是我不解的地方

  • 模板化情况下,编译f2时,编译器考虑使用Foo::operator*而不是 Bar::operator*,而在非模板化 情况下,它会考虑同时使用两者(并且由于歧义而拒绝更进一步)。 是什么让编译器的行为有所不同?

  • 我的库 Bar 的用户将在 Bar:: 命名空间之外,但我希望使用 Bar::operator*,而不是 Foo::运算符*。我考虑过显式调用 Bar::operator*(3.f,a),这很丑陋,或者在全局命名空间中插入我自己的运算符,我认为它是一个 BadThing . 有没有我遗漏的选项,或者我做错了什么?

最佳答案

In the templated case, when compiling f2, the compiler considers using Foo::operator* but not Bar::operator*, while in the non-templated case, it considers using both (and refuses to go further because of the ambiguity). What makes the compiler behave differently ?

在这两种情况下,编译器都会考虑同时使用两者,但在模板化 operator* 的情况下,调用不会产生歧义,因为存在一个参数类型与参数完全匹配的非模板化函数 (尝试将 3.f 替换为 3.,您将看到找到了模板版本)。通常:

template <typename T>
void g (T) { }

void g (float) { }

g(0.f); // Ok, the overload for float is preferred over the templated version

A user of my library Bar will be outside the Bar:: namespace, yet I want Bar::operator* to be used, and not Foo::operator*. I considered explicitely calling Bar::operator*(3.f,a), which is ugly, or inserting my own operator in the global namespace, which I reckon is a Bad Thing. Is there an option I am missing, or am I doing something wrong ?

不幸的是,ADL 不会找到您的重载,因为 operator* 的唯一参数是 floatMyDeriv,它们是在命名空间 。一种可能的方法是从 Foo::Deriv 继承:

namespace Bar {
struct MyDeriv: public Foo::Deriv {};
MyDeriv operator* (float x, const MyDeriv& d) { return MyDeriv();}
}

另一种方法是在 Foo 命名空间内为 operator* 声明重载:

namespace Bar {
typedef Foo::Deriv MyDeriv;
}

namespace Foo {
Bar::MyDeriv operator* (float x, const Bar::MyDeriv& d) { return Bar::MyDeriv(); }
}

关于c++ - 运算符重载、名称解析和命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38329694/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com