2010-11-11 18 views
14

mam coś takiego:ADL z typedefs z innej przestrzeni nazw

#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; 
} 

To oczywiście nie działa, ponieważ nie ADL znajdzie operator<< ponieważ namespace N nie jest związany z MyPair (niestety). Afaik nie może dodawać do przestrzeni nazw std, więc jeśli zdecyduję się zdefiniować operator << w standardzie, byłoby to trochę nielegalne. Więc ... co robić w takich sytuacjach? Nie chcę jednoznacznie kwalifikować operator <<, ani nie chcę pisać using namespace N. Tak więc, pytania są następujące:

  1. Jak zmienić kod?
  2. Dlaczego ADL nie powinien łączyć przestrzeni nazw typedef? Poważne powody? Byłoby miło, np. w tym przypadku. Dzięki

Odpowiedz

3
  1. Można by stworzyć swój własny typ w przestrzeni nazw N, ewentualnie dziedziczenie z std :: pair. Możesz dodać "używając przestrzeni nazw N;" wewnątrz głównej. Ten pierwszy jest bardziej przydatny.

  2. Ponieważ typ jest zdefiniowany w innym obszarze nazw i nie można go zdefiniować na dwa.

Przykład:

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 
}; 
} 

Jeśli używany jako std :: pair nie jest ważne, można upuścić dziedziczenia i zmiana nazwy członków. W obu przypadkach można oczywiście dodać dodatkowe metody, ale jeśli zachować dziedzictwo Można użyć „metody zmiany nazwy”:

int  & foo()  { return first; } 
int const& foo() const { return first; } 
double  & bar()  { return second; } 
double const& bar() const { return second; } 
+0

byłem thinki Sam o tym, ale wydaje mi się to sztuczne dla mnie ... –

+0

@Armen: Co wydaje się sztuczne? –

+2

@Roger: Tworzenie nowej klasy tylko ze względu na ADL –

1

Jeśli masz konkretny typ danych, które chcesz do wyjścia, zawsze można zdefiniuj własną klasę zamiast używać std::pair.

struct myPair 
{ 
    int first; 
    double second; 
}; 
+0

Jak by to pomogło? –

+0

Co z dobrą starą zasadą ponownego użycia kodu?:) –

+1

@Let_Me_Be: To pomogłoby, ponieważ wtedy ADL znalazłoby operatora << w przestrzeni nazw N –

3

Nie mogę wymyślić powodu, dlaczego nazwy typedef nie powinny uczestniczyć w ADL. Co więcej, to sprawia, że ​​po wprowadzeniu kodu zdefiniowane:

#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(), [...]); 
} 
  • Jeśli std::vector<T>::iterator jest typedef dla czegoś, co siedzi w przestrzeni nazw std: std::for_each zostanie wywołana
  • Jeśli std::vector<T>::iterator jest typedef dla my::A *: kompilator powinien narzekać, że my::for_each nie bierze 3 argumenty
+0

+1 za ładny przykład! –

1

To jest mogą dodawać specjalizacji funkcje szablonu do namespace::std, jednak ponieważ żaden z typów użytych w MyPair jest zdefiniowany przez użytkownika, nie jestem pewna taka specjalizacja jest legalna.

namespace std { 
    template<> 
    ostream& operator<<(ostream& os, const MyPair& p) { } 
} 
2

Twoje opcje to:

  • Definiowanie nowego typu, które wykorzystuje std :: pair w jego realizacji, zamiast używać typedef
  • użyć innej nazwy dla swojej funkcji wyjścia
  • Jawnie zakwalifikuj żądaną funkcję, gdy ją nazwiesz
  • (być może) Specjalizuj funkcję w przestrzeni nazw std (nie jestem pewien, czy pair<int,double> liczy się jako UDT)

Wszystko to wynika z głównej siły i słabości typedefs: nazwy typedef są po prostu synonimami. Nie ma znaczenia, w którą przestrzeń nazw się wpisuje, nazwa typedef odnosi się do skojarzonego typu, w jakiejkolwiek przestrzeni nazw, która jest zdefiniowana w. Jest ona różna od typu, który jest nowym typem, który można przekształcić do/z powiązanego typu. Wyobraź sobie ten scenariusz:

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

Jest to nieważne, ponieważ int i id_t nie są różnymi typami. To rozciąga się na 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 

A oto pytanie dla Ciebie: Czy uważasz, że następujące kompilacje nie powiodłyby się? Jeśli nie, w jaki sposób powinny nazwa odnośnika zostać rozwiązany:

B::id_t id; 
g(id); 
+0

Cóż, tak, uważam, że nie powinien, najlepiej, nie kompilować. Wyszukanie nazwy przebiegałoby w następujący sposób: jeśli wyrażenie argumentu jest identyfikatorem zadeklarowanym za pomocą typu typedefed, powiązane przestrzenie nazw w poszukiwaniu g muszą zawierać przestrzeń nazw, w której deklarowany jest typedef. Coś w tym stylu ... Ale dając mu trochę myśli, że czuję, że to będzie hifi i bezużyteczne i problematyczne ... –

0

rozwiązać ten problem poprzez pociągnięcie odpowiedniego symbolu (ów) do nazw chcę z nich korzystać od:

#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; 
} 
2

Można użyć silna 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; 
} 

(. dodatkowy typedef jest nadal konieczne w celu uniknięcia dodatkowego przecinek w makro)

Powiązane problemy