2

I am using a library that is under a namespace, let's call it Hello.

namespace Hello {

template<class T>
void World(std::ostream& os, const T& t) {
    os << t;
}

}

The class T is something like std::array<int,10> and I also write an ostream overload function for it. However, calling Hello::World(arr) leads to compile errors that say the compiler cannot find the overload for operator<<().

After some search, I come up with a solution that explains this situation. How does the operator overload resolution work within namespaces? and Name resolution of functions inside templates instantiated with qualified types.

So we can simplify the situation like this.

void f(int) {}
void f(int,int) {}

namespace Hello {
    using ::f;
    void f(int,int,int) {}
    void World()
    {
        f(100);
        f(100, 200);
        f(100, 200, 300);
    }
};

int main()
{
    Hello::World();
    return 0;
}

Without the using ::f; line, this code fails to be compiled since the name f can hide ALL of the functions with the same name in the global namespace.

Now that this is my problems:

  1. Since namespace Hello { .... } is in the library, I shall not modify it. That is, I cannot modify the implementation inside World(). The only solution is to put a line namespace Hello { using ::f; } somewhere in my code. Is it a good practice, or there is a more elegant solution?
  2. In this example, can I only import f(int) and not f(int,int)?
johnjohnlys
  • 394
  • 1
  • 9

1 Answers1

2

Is it a good practice, or there is a more elegant solution?

IMHO, you can use it with third party library. It is clear and expressive enough. It would be better if you could write:

void World() {
    ::f(100);           // f from global namespace
    ::f(100, 200);      // f from global namespace
    f(100, 200, 300);   // f NOT from global namespace
}

because then it is clearly visible which function is and which is not from the global namespace but this solution does not work for you since you cannot modify implementation of World function.

Can I only import f(int) and not f(int, int)?

Yes. You can do the following in order to import only f(int) function:

void f(int) {}

namespace Hello {
    using ::f;    // only void f(int) is defined before this line
                  // therefore, it is the only overload being imported to the Hello namespace
}

void f(int,int) {}

Demo

UPDATE

If you want to import only one overload of an operator<<, not an ordinary function, then you could wrap each overload in a separate namespace like this:

namespace XX {

struct X {
    int x;
};

std::ostream& operator<<(std::ostream& os, X const& x) {
    return os;
}

}

namespace YY {

std::ostream& operator<<(std::ostream& os, Y const& y) {
    return os;
}

struct Y {
    double y;
};

}

namespace Hello {
    using ::XX::X;
    using ::XX::operator<<;
    using ::YY::Y;
}

Check it out live.

NutCracker
  • 11,485
  • 4
  • 44
  • 68
  • Thanks for your solution, but I still have some concerns. 1. As I said, since Hello::World is a template library function that I cannot modify (something like boost::whatever), so I cannot not have it call the global one explicitly. 2. Changing the order of declaration is elegant. However, f() is indeed the operator<<, so I would like a solution that can explicitly import only the one I need. – johnjohnlys Feb 16 '20 at 09:27
  • @johnjohnlys 1. I wrote that I understand you cannot call the global one explicitly. I just mentioned that as an addition. 2. Can you use something like [this](https://godbolt.org/z/AmQv2a)? – NutCracker Feb 16 '20 at 09:45
  • Creating another namespace and import that is a brilliant idea! Thanks. – johnjohnlys Feb 16 '20 at 14:00