词法范围的排序行为
Posted
技术标签:
【中文标题】词法范围的排序行为【英文标题】:Lexically-scoped ordering behavior 【发布时间】:2010-10-21 14:33:03 【问题描述】:我有一个有两个排序定义的类。 (在真正的问题中,一个是全阶,一个是半阶。)但是能够使用比较运算符而不是总是必须使用显式比较函数或仿函数对象是很好的。所以我想我会提供一些这样的比较运算符:
class C;
namespace Order1
bool operator< (const C&, const C&);
namespace Order2
bool operator< (const C&, const C&);
>
、<=
、>=
的运算符当然也被定义了,但这不是重点。现在用户可以在文件范围或块范围内说 using namespace Order1;
或 ... Order2
并获得该文件/块其余部分的请求行为。
如果可能的话,我想改进的令人失望的部分是这些using
s 不能嵌套。
void g(const C&, const C&);
using namespace Order1; // for most functions in this file
void f(const C& x, const C& y)
bool test1 = x < y; // Order1
// Would like to switch to Order2 for this block.
using namespace Order2;
bool test2 = x < y; // Ambiguous overload!
g(x, y); // Unaffected by local using-s.
由于using
-directives 在同一个命名空间中使用时不会隐藏任何内容,因此这并不能很好地暂时反转块作用域中运算符的含义。
另一个相关的想法是允许堆栈上的虚拟对象的构造函数和析构函数操纵要使用的行为的“当前设置”。但我不认为我想在这种情况下采取这种方式,因为这意味着上面 f
的等价物可能会改变其他称为 g
的函数的行为。
是否有另一种方法可以获得类似的效果,但允许嵌套操作与最里面的块“隐藏”其他块?或者我是否坚持每个声明区域的重载运算符的一种行为?我想这是可以管理的,因为代码仍然可以显式使用函数或仿函数,而不是使用运算符。
【问题讨论】:
显式好,隐式不好。大致。恕我直言。 :-) 干杯, 我没有提到的一件事是,这是对已经拥有这些运算符并被数千个文件使用的现有类的更改。所以我坚持提供一个“默认”的操作员行为,这很像旧的行为。但我想我会推荐新代码使用显式函数或仿函数,而不是完全弄乱运算符。我只是希望一些同事接受建议。 【参考方案1】:我会坚持使用普通的比较函数。其余的代码会更干净。没有using namespace...
或显式调用作用域operator<
。这样更容易阅读,IMO...
int main()
bool b = compare1(4, 5);
b = compare2(4, 5);
【讨论】:
【参考方案2】:而不是使用命名空间 Order2 放入
bool test2 = Order2::operator<(x, y);
这将在这种情况下工作。如果您想“元程序”,即能够将 Order1 / Order2 作为模板参数传递,您应该使用 operator
【讨论】:
如果它需要更具体的语法,我宁愿只使用Order2::compare(x,y) < 0
,或者继承std::binary_function<C,C,bool>
的仿函数Order2::Comp()
。我想我只是为了自己的利益而懒惰。
如果你使用一个类,你可以重载 operator()。您需要创建该类的“虚拟”实例。然后你使用 compareObj(x,y)。【参考方案3】:
为什么不废弃命名空间,只声明两个具有不同参数类型的operator <
重载,每个类类型一个?
更新
正如 dgnorton 在下面的评论中指出的那样,您有一个类,上面定义了两种不同的顺序。这似乎是问题的可能原因。是否可以将其分成两个不同的类?
【讨论】:
在他的情况下,类类型是相同的......他希望同一个运算符有不同的行为......这可能不是一个好主意。 如果他打算将谓词传递给算法或 std::set 或类似方法以给出不同的排序,这可能是个好主意。如果他将映射放入每个命名空间,它可能会自动从该命名空间中获取运算符,尽管 Koenig Lookup 建议它可能首先查看类本身的命名空间。以上是关于词法范围的排序行为的主要内容,如果未能解决你的问题,请参考以下文章