ADL с typedefs из другого пространства имен
У меня есть что-то вроде этого:
#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;
}
Это, естественно, не работает, потому что ADL не найдет operator<<
, потому что namespace N
не связан с MyPair
(к сожалению). Afaik нельзя добавить в пространство имен std, поэтому, если бы я решил определить operator <<
в std, что было бы незаконным. Итак... что делать в таких ситуациях? Я не хочу явно квалифицировать operator <<
, и я не хочу писать using namespace N
. Итак, вопросы:
- Как реорганизовать код?
- Почему ADL не связывает пространства имен typedefs? Серьезные причины? Было бы неплохо, например. в этом случае. Благодаря
Ответы
Ответ 1
-
Вы можете создать свой собственный тип в пространстве имен N, возможно, наследуя от std:: pair. Вы можете добавить "using namespace N;" внутри основной. Первый, скорее всего, будет полезен.
-
Поскольку тип определен в другом пространстве имен и не может быть определен двумя.
Пример:
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
};
}
Если использование в качестве std:: пары не важно, вы можете удалить наследование и переименовать элементы. В любом случае вы можете, конечно, добавить дополнительные методы, но если вы сохраните наследование, вы можете использовать "методы переименования":
int & foo() { return first; }
int const& foo() const { return first; }
double & bar() { return second; }
double const& bar() const { return second; }
Ответ 2
Я не могу придумать, почему имена typedef
не должны участвовать в ADL. Кроме того, он определяет следующую реализацию кода:
#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
является typedef для того, что находится в пространстве имен std: std::for_each
будет называться
- Если
std::vector<T>::iterator
является typedef для my::A *
: компилятор должен жаловаться, что my::for_each
не принимает 3 аргумента
Ответ 3
Ваши варианты:
- Определите новый тип, который использует std:: pair в своей реализации, вместо использования typedef
- Используйте другое имя для функции вывода
- Явно квалифицирую функцию, которую вы хотите, когда вы ее называете
- (Может быть) Специализируйте функцию в пространстве имен std (я не уверен, что
pair<int,double>
считается UDT)
Все это проистекает из основной силы и слабости typedefs: typedef имена - всего лишь синонимы. Неважно, какое пространство имён вы введете, имя typedef относится к ассоциированному типу, в любом пространстве имен, в котором этот тип определен. Это отличается от того, что typedef является новым типом, который конвертируется в/из связанного типа. Представьте себе этот сценарий:
class C{};
typedef C id_t;
void f(C);
int f(id_t); // error: structurally equivalent to `int f(C);`
Это недопустимо, потому что int и id_t не являются отдельными типами. Это распространяется на 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
И вот вопрос для вас: считаете ли вы, что следующее не должно компилироваться? Если нет, как следует искать поиск имени:
B::id_t id;
g(id);
Ответ 4
Вы можете использовать сильный 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;
}
(Дополнительный typedef по-прежнему необходим, чтобы избежать дополнительной запятой в макросе.)
Ответ 5
Если у вас есть определенный тип данных, который вы хотите вывести, вы всегда можете определить свой собственный класс, а не использовать std::pair
.
struct myPair
{
int first;
double second;
};
Ответ 6
В нем есть, чтобы добавить специализацию функций шаблона к namespace::std
, однако, поскольку ни один из типов, используемых в MyPair
, не определяется пользователем, я не уверен, что такая специализация является законной.
namespace std {
template<>
ostream& operator<<(ostream& os, const MyPair& p) { }
}
Ответ 7
Я решаю эту проблему, потянув соответствующий символ (символы) в пространство имен, в котором я хочу их использовать:
#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;
}