ADL with typedefs from another namespace

I have something like this:

#include <iostream> namespace N { typedef std::pair<int, double> MyPair; std::ostream& operator << (std::ostream& o, MyPair const & mypair) { /// } } int main() { N::MyPair pr; std::cout << pr; } 

This, of course, does not work because ADL will not find operator<< , because namespace N not associated with MyPair (unfortunately). Afaik cannot be added to the std namespace, so if I decided to define operator << in std, that would be illegal. So ... what to do in such situations? I do not want to explicitly qualify operator << , and I do not want to write using namespace N So the questions are:

  • How to reorganize the code?
  • Why doesn't ADL bind typedefs namespaces? Serious reasons? It would be nice, for example. in this case. Thanks
+14
c ++ typedef argument-dependent-lookup
Nov 11 '10 at 2:35 a.m.
source share
7 answers
  • You can create your own type in the N namespace, possibly inheriting from std :: pair. You can add "using namespace N;" inside the main one. The first is likely to be useful.

  • Because the type is defined in another namespace and cannot be defined by two.

Example:

 namespace N { struct MyPair : std::pair<int, double> { MyPair(int first, double second) : std::pair<int, double>(first, second) {} // add defaults if desired: first=0, second=0.0 // with defaults, you may want to make the ctor explicit or leave implicit // also, if desired and you don't use two defaults above: MyPair() : std::pair<int, double>(0, 0.0) {} // in 0x, you can "import" the base ctors with a using declaration }; } 

If using std :: as a pair is not important, you can remove the inheritance and rename the elements. In any case, you can, of course, add additional methods, but if you keep the inheritance, you can use the "rename methods":

 int & foo() { return first; } int const& foo() const { return first; } double & bar() { return second; } double const& bar() const { return second; } 
+3
Nov 11 2018-10-11
source share

I cannot think of why typedef names should not participate in ADL. In addition, it defines the following code implementation:

 #include <algorithm> #include <vector> namespace my { class A {}; void for_each(); } // my int main() { std::vector<my::A> v; for_each(v.begin(), v.end(), [...]); } 
  • If std::vector<T>::iterator is a typedef for what is in the std namespace: std::for_each will be called
  • If std::vector<T>::iterator is a typedef for my::A * : the compiler should complain that my::for_each does not accept 3 arguments
+3
Nov 11 2018-10-11
source share

Your options:

  • Define a new type that uses std :: pair in its implementation, instead of using typedef
  • Use a different name for the output function.
  • Explicitly qualify the function you want when you call it
  • (Maybe) Specialize the function in the std namespace (I'm not sure if pair<int,double> is considered UDT)

All this stems from the core strengths and weaknesses of typedefs: typedef names are just synonyms. No matter what namespace you enter, the name typedef refers to the associated type, in any namespace in which that type is defined. This is different from the fact that typedef is a new type that converts to / from the associated type. Imagine this scenario:

 class C{}; typedef C id_t; void f(C); int f(id_t); // error: structurally equivalent to `int f(C);` 

This is not valid because int and id_t are not separate types. This applies to ADL:

 namespace A{ class C{}; void f(C); void g(C); } namespace B{ typedef C id_t; int f(id_t); // structurally equivalent to `void f(C);` } B::id_t id; // completely equivalent to `A::C id;` int n = f(id); // error: A::f doesn't return int 

And here is the question for you: do you think the following should not compile? If not, how to search for a name search:

 B::id_t id; g(id); 
+2
Nov 11 2018-10-11
source share

You can use strong typedef:

 #include<boost/strong_typedef.hpp> #include<iostream> namespace N { // typedef std::pair<int, double> MyPair; typedef std::pair<int, double> pair_int_double; BOOST_STRONG_TYPEDEF(pair_int_double, MyPair); std::ostream& operator << (std::ostream& o, MyPair const & mypair) { return o; } } int main(){ N::MyPair pr; std::cout << pr; } 

(An extra typedef is still needed to avoid an extra comma in the macro.)

+2
Jan 14 '15 at 10:13
source share

If you have a specific data type that you want to output, you can always define your own class, rather than using std::pair .

 struct myPair { int first; double second; }; 
+1
Nov 11 2018-10-11
source share

It is there to add a specialization of template functions to namespace::std , however, since none of the types used in MyPair are user-defined, I'm not sure that such specialization is legal.

 namespace std { template<> ostream& operator<<(ostream& os, const MyPair& p) { } } 
+1
Nov 11 '10 at 15:45
source share

I solve this problem by pulling the appropriate character (s) into the namespace in which I want to use them:

 #include <iostream> namespace N { typedef std::pair<int, double> MyPair; std::ostream& operator << (std::ostream& o, MyPair const & mypair) { /// } } using N::operator <<; // now it should compile int main() { N::MyPair pr; std::cout << pr; } 
0
Jul 12 '14 at 13:53 on
source share



All Articles