【问题标题】:Can I namespace the ostream << operator?我可以命名 ostream << 运算符吗?
【发布时间】:2019-05-15 23:37:00
【问题描述】:

正如之前回答的那样,namespacing operator overloads is considered good practice,所以这就是我想要做的。

问题:如果我不这样做,它只会编译。是我做错了,还是发现了不可能的异常?

这是一个便于复制的翻译单元:

// lib/halfseconds.h:
#include <chrono>

namespace lib {
    using halfseconds = std::chrono::duration<intmax_t, std::ratio<1, 2> >;
}

// lib/debug.h:
#include <ostream>

namespace lib {
    std::ostream& operator<<(std::ostream& o, lib::halfseconds halves)
    {
        double seconds = halves.count();
        seconds /= lib::halfseconds::period::den;
        o << seconds << 's';
        return o;
    }
}

// demo/main.cpp:
#include <iostream>

int main()
{
    lib::halfseconds threeHalvseconds(3);
    std::cout << threeHalvseconds << '\n'; // 1.5s
}

编译器是怎么说的? G++ 版本 8.2.1 说 «no match for operator

【问题讨论】:

  • 这与它被标记为重复的问题之间的一个区别似乎是在这种情况下将operator&lt;&lt; 放入命名空间lib 并不能像解决其他问题一样解决问题。
  • 没有。 “命名空间”是一个名词。你不能动词它。
  • 我可以动词“空间”,因此我可以动词“命名空间”。

标签: c++ namespaces operator-keyword


【解决方案1】:

您尝试使用的原理称为Argument Dependent Lookup。如果我在同一个命名空间中声明了一个函数和一个类型,我可以在命名空间之外一起使用它们,而无需指定函数来自哪个命名空间:

//In MyClass.h
namespace foo {
    class MyClass { /* stuff */ }; 
}
//In doStuff.h
namespace foo {
    void doStuff(MyClass c) { /* stuff */ }
}

//in main.cc
int main() {
    foo::MyClass tom; //I'm bad with names
    doStuff(tom); //Here, we don't have to specify the namespace
}

几乎在您的示例中发生了。不同之处在于halfseconds 实际上并未在命名空间lib 中声明。因为halfseconds是一个别名,它实际上是在std::chrono中声明的,当你把operator&lt;&lt;重载放到命名空间lib中时,编译器不会检查它。

如何解决这个问题

解决这个问题的最简单方法是在命名空间 lib 中声明一个新类型:

// lib/halfseconds.h:
#include <chrono>

namespace lib {
    class halfseconds 
        : public std::chrono::duration<intmax_t, std::ratio<1, 2>> 
    {
       public:
        using Base = std::chrono::duration<intmax_t, std::ratio<1, 2>>;
        using Base::Base; //Use the constructor
    };
}

// lib/debug.h:
#include <ostream>

namespace lib {
    std::ostream& operator<<(std::ostream& o, lib::halfseconds halves)
    {
        double seconds = halves.count();
        seconds /= lib::halfseconds::period::den;
        o << seconds << 's';
        return o;
    }
}

// demo/main.cpp:
#include <iostream>

int main()
{
    lib::halfseconds threeHalvseconds(3);
    std::cout << threeHalvseconds << '\n'; // 1.5s
}

您可以在任何使用std::chrono::duration 的地方使用它,它具有所有相同的功能,并且因为它是在lib 命名空间中定义的,所以它可以与lib 命名空间中的任何其他函数一起使用,而无需前缀lib!

【讨论】:

    【解决方案2】:

    这里的问题是,一旦你将 operator

    要么:

    • 使用 lib::operator
    • lib::operator

    【讨论】:

    • 赞成,但这里有更多信息:当此代码升级到 C++20 时,第一个项目符号将导致冲突,因为 C++20 为 lib::halfseconds 添加了一个流操作符(即std::chrono::duration 的类型别名)。修复方法是删除lib::operator&lt;&lt;,但输出的语法随后将更改为3[1/2]s
    猜你喜欢
    • 1970-01-01
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-26
    • 2013-11-28
    • 2021-12-16
    • 1970-01-01
    相关资源
    最近更新 更多