Могу ли я указать пространство имен оператора ostream <<? - PullRequest
0 голосов
/ 14 декабря 2018

Как уже отвечалось ранее, перегрузки операторов пространства имен считаются хорошей практикой , поэтому я хочу это сделать.

Проблема: Она компилируется, только если я этого не сделаю.Я просто делаю это неправильно или я нашел исключение, когда это невозможно?

Вот одна единица перевода для простого воспроизведения:

// 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
}

Что говорит компилятор?Версия 8.2.1 для G ++ говорит «нет совпадения для оператора <<» и выбрасывает один пугающий список (208 строк) кандидатов.Я полагаю, что ни один из них не имеет отношения, поскольку я не получил бы эту ошибку, если бы соответствующая ошибка не отсутствовала. </p>

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Принцип, который вы пытаетесь использовать, называется 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, его можно использовать с любыми другими функциями в пространстве имен lib без префикса lib!

0 голосов
/ 15 декабря 2018

Проблема здесь в том, что после того, как вы поместили operator << в пространство имен, вы должны явно указать компилятору, что вы хотели бы использовать пространство имен, иначе оно скрыто. </p>

Либо:

  • с использованием lib :: operator << внутри основного </li>
  • lib :: operator << (std :: cout, threeHalvseconds) << '\ n'; </li>
...