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指出“操作符<<>不匹配”,并生成一张令人生畏的候选列表(208行)。我想这些都不相关,因为如果没有相关的错误,我不会得到这个错误。
答案 0 :(得分:3)
这里的问题是,一旦将operator <<放在命名空间中,就应该明确告诉编译器您要使用该命名空间,否则它将被隐藏。
要么:
答案 1 :(得分:2)
您要尝试使用的原理称为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<<
重载放在命名空间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
命名空间中定义的,因此可以与{{1 }}命名空间,而不必加前缀lib
!