C++ Reenviar declaración usando directiva

2 minutos de lectura

Tengo un encabezado que expone una clase con plantilla y un typedef mediante el uso, algo como:

namespace fancy {

  struct Bar {
     ...
  }

  template<typename T>
  class Foo {
     ...
  }

  using FooBar = Foo<Bar>;
}

Me gustaría reenviar declarar FooBar para usarlo en un shared_ptr en otro encabezado. He intentado

namespace fancy {
  using FooBar;
}

como para una clase o estructura, pero sin suerte. ¿Es posible? y si lo es, cómo?

No puedes declarar un using alias sin definirlo. Sin embargo, puede declarar su plantilla de clase sin definirla y usar un duplicado using alias:

namespace fancy {
    template <typename> class Foo;
    class Bar;
    using FooBar = Foo<Bar>;
}

  • Si pruebo eso, obtengo error: 'using FooBar = class Foo<Bar>' has a previous declaration as 'using FooBar = class Foo<Bar>' con gcc 4.8.1.

    – Mike M.

    20 de noviembre de 2013 a las 22:46


  • Ambos heads relativamente recientes de gcc (4.9.0 20131031 (experimental)) y clang (versión 3.4 (tronco 193991)) compilan el código que consta de mis declaraciones sin su código (se corrige agregando punto y coma y eliminando ...) sin problemas. Clang se queja de un desajuste entre struct y class por Barsin embargo.

    – Dietmar Kühl

    20 de noviembre de 2013 a las 22:53

Si su declaración de uso es demasiado grande (muchos parámetros de plantilla, que a su vez también están definidos por una declaración de uso), también puede agregar un dummy delantero estructura que tiene el tipo de uso como un tipo dependiente:

    namespace fancy {

        struct Bar {
            ...
        }

        template<typename T>
        class Foo {
            ...
        }

        using FooBar = Foo<Bar>;

        // Forward struct
        struct FooBarFwd {
            using type = FooBar;
        }
    }

Luego, en su lugar donde desea reenviar, declare:

    namespace fancy {
        class FooBarFwd;
    }
    // use your type as
    typename FooBarFwd::type baz(const typename FooBarFwd::type & myFooBar);
    // instead of
    // FooBar baz(const FooBar & myFooBar);

Algunas desventajas de este enfoque son

  • Usando typename para eliminar la ambigüedad del tipo dependiente.
  • Indirección adicional para su tipo, algunos compiladores podrían tener problemas al informar errores.
  • Cambiar a este enfoque puede necesitar muchos cambios en su código (cambiar cada aparición de FooBar con typename FooBarFw::type)

Por lo tanto, aconsejo aplicar esta técnica solo cuando esté seguro de lo que está haciendo.

Otra forma de usar la declaración hacia adelante es reemplazar using con la clase de herencia:

// using FooBar = Foo<Bar>;
class FooBar : public Foo<Bar> {};

por supuesto, ahora FooBar no es lo mismo que Foo<Bar>. Por ejemplo, necesita heredar constructores posiblemente existentes a través de using Foo<Bar>::Foo, pero como beneficio, puede usar easy forward declare como de costumbre. Sólo:

namespace fancy {
    class FooBar;
}

¿Ha sido útil esta solución?