2010-11-11 15 views
14

que tiene algo como esto:ADL con typedefs desde otro espacio de nombres

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

Naturalmente, esto no funciona, porque no encontrará ADL operator<< porque namespace N no está asociada con MyPair (por desgracia). Afaik one no puede agregarse al espacio de nombres std, por lo que si elijo definir operator << en std sería algo ilegal. Entonces ... ¿qué hacer en tales situaciones? No quiero calificar explícitamente operator <<, ni deseo escribir using namespace N. Entonces, las preguntas son:

  1. Cómo refactorizar el código?
  2. ¿Por qué ADL no asociaría los espacios de nombres de typedefs? ¿Razones serias? Sería bueno, por ejemplo en este caso. Gracias

Respuesta

3
  1. Usted puede crear su propio tipo de espacio de nombres N, posiblemente, heredando de std :: pair. Puede agregar "using namespace N"; dentro principal. El primero es más probable que sea útil.

  2. Porque el tipo se define en otro espacio de nombres y no se puede definir en dos.

Ejemplo:

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

Si se utiliza como un std :: pair no es importante, se puede eliminar la herencia y cambiar el nombre de los miembros. En cualquiera de los casos se puede, por supuesto, añadir métodos adicionales, pero si se mantiene la herencia puede utilizar "métodos de cambio de nombre":

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

I era thinki ng al respecto, pero parece artificial para mí ... –

+0

@Armen: ¿Qué parece artificial? –

+2

@Roger: Creación de una nueva clase sólo por el bien –

1

Si usted tiene un tipo de datos específico que desea emitir, siempre se puede defina su propia clase en lugar de usar std::pair.

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

¿Cómo ayudaría eso? –

+0

¿Qué hay del buen principio de reutilización de código?:) –

+1

@Let_Me_Be: Eso ayudaría porque entonces ADL encontraría el operador << en el espacio de nombres N –

3

no puedo pensar en una razón por typedef nombres no deben participar en las AVD. Además, se hace la siguiente implementación del código definido:

#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(), [...]); 
} 
  • Si std::vector<T>::iterator es un typedef para algo que se encuentra en el espacio de nombres std: std::for_each se llamará
  • Si std::vector<T>::iterator es un typedef para my::A *: el compilador debe quejarse de que my::for_each no toma 3 argumentos
+0

+1 para el buen ejemplo! –

1

Se se Anadir especialización de la plantilla funciona a namespace::std, sin embargo, dado que ninguno de los tipos utilizados en MyPair es definido por el usuario, no soy seguro tal especialización es legal.

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

Sus opciones son:

  • definir un nuevo tipo que utiliza std :: pair en su aplicación, en lugar de utilizar typedef
  • utilizar un nombre diferente para su función de salida
  • Califique explícitamente la función que desea cuando la llame
  • (Quizás) Especialice la función en el espacio de nombres std (no estoy seguro de si pair<int,double> cuenta como UDT)

Todo esto proviene de la principal fortaleza y debilidad de typedef: typedef nombres son sólo sinónimos. No importa qué espacio de nombres lo pones en, el nombre typedef se refiere al tipo asociado, en cualquier espacio de nombres que tipo se define en. Esto es distinto de un typedef ser un nuevo tipo que es convertible a/desde el tipo asociado. Imagine este escenario:

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

Esto no es válido, porque int e id_t no son tipos distintos. Esto se extiende a 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 

Y esta es una pregunta para usted: ¿Considera que no debería compilarse lo siguiente? Si no, ¿cómo se debe resolver la búsqueda de nombres:

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

Bueno, sí, creo que no debería, idealmente, no compilar. La búsqueda del nombre procedería de la siguiente manera: si la expresión del argumento es un identificador que se declaró con un typedefed-type, entonces los espacios de nombres asociados para buscar g deben incluir el espacio de nombres en el que se declaró el typedef ... Algo así ... Pero ... pensándolo bien, siento que sería hideos e inútil y problemático ... –

0

puedo solucionar este problema tirando el símbolo correspondiente (s) en el espacio de nombres que quiero utilizarlas desde:

#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

Se puede utilizar una fuerte 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; 
} 

(. el typedef extra es todavía necesario para evitar la coma extra en la macro)

Cuestiones relacionadas