Reputation: 132974
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:
Upvotes: 19
Views: 2667
Reputation: 16242
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.)
Upvotes: 2
Reputation: 48605
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;
}
Upvotes: 2
Reputation:
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; }
Upvotes: 4
Reputation: 8516
Your options are to:
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);
Upvotes: 2
Reputation: 114695
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) { }
}
Upvotes: 1
Reputation: 76745
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(), [...]);
}
std::vector<T>::iterator
is a typedef for something which sits in the std namespace : std::for_each
will be calledstd::vector<T>::iterator
is a typedef for my::A *
: the compiler should complain that my::for_each
doesn't take 3 argumentsUpvotes: 4
Reputation: 53289
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;
};
Upvotes: 1