问题
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 naturally doesn't work, because ADL won't find operator<<
because namespace N
is not associated with MyPair
(unfortunately). Afaik one may not add to namespace std, so if I chose to define operator <<
in std that would be kinda illegal. So... what to do in such situations? I don't want to explicitly qualify operator <<
, nor do I wish to write using namespace N
. So, questions are:
- How to refactor the code?
- Why wouldn't ADL associate namespaces of typedefs? Serious reasons? It would be nice, e.g. in this case. Thanks
回答1:
You could create your own type in namespace N, possibly inheriting from std::pair. You could add "using namespace N;" inside main. The former is more likely to be useful.
Because the type is defined in another namespace and cannot be defined in 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's ctors with a using declaration
};
}
If being used as a std::pair isn't important, you can drop the inheritance and rename the members. In either case you can, of course, add additional methods, but if you keep the inheritance you can use "renaming methods":
int & foo() { return first; }
int const& foo() const { return first; }
double & bar() { return second; }
double const& bar() const { return second; }
回答2:
I can't think of a reason why typedef
names should not participate in ADL. Furthermore, it makes the following code implementation defined :
#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 something which sits in the std namespace :std::for_each
will be called - If
std::vector<T>::iterator
is a typedef formy::A *
: the compiler should complain thatmy::for_each
doesn't take 3 arguments
回答3:
Your options are to:
- Define a new type which uses std::pair in its implementation, instead of using typedef
- Use a different name for your output function
- Explicitly qualify the function you want when you call it
- (Maybe) Specialize the function in namespace std (I'm not sure if
pair<int,double>
counts as a UDT)
This all stems from the main strength and weakness of typedefs: typedef names are just synonyms. It doesn't matter what namespace you put it in, the typedef name refers to the associated type, in whatever namespace that type is defined in. This is distinct from a typedef being a new type that is convertible 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 invalid, because int and id_t aren't distinct types. This extends 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's a question for you: Do you believe that the following should fail to compile? If not, how should the name lookup be resolved:
B::id_t id;
g(id);
回答4:
You can use a 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;
}
(The extra typedef is still necessary to avoid the extra comma in the macro.)
回答5:
If you have a specific data type which you want to output, you can always define your own class rather than use std::pair
.
struct myPair
{
int first;
double second;
};
回答6:
It is allowed to add specialization of template functions to namespace::std
however since none of the types used in MyPair
is user defined I'm not sure such a specialization is legal.
namespace std {
template<>
ostream& operator<<(ostream& os, const MyPair& p) { }
}
回答7:
I solve this problem by pulling the relevant symbol(s) into the namespace I want to use them from:
#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;
}
来源:https://stackoverflow.com/questions/4155450/adl-with-typedefs-from-another-namespace