36

I have a header which exposes a templated class and a typedef via using, something like:

namespace fancy {

  struct Bar {
     ...
  }

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

  using FooBar = Foo<Bar>;
}

I would like to forward declare FooBar to use it in a shared_ptr in another header. I've tried

namespace fancy {
  using FooBar;
}

like for a class or struct, but without luck. Is this possible, and if so, how?

Mike M
  • 2,263
  • 3
  • 17
  • 31

3 Answers3

27

You can't declare a using alias without defining it. You can declare your class template without defining it, however, and use a duplicate using alias:

namespace fancy {
    template <typename> class Foo;
    class Bar;
    using FooBar = Foo<Bar>;
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • If I try that, I get `error: 'using FooBar = class Foo' has a previous declaration as 'using FooBar = class Foo'` with gcc 4.8.1. – Mike M Nov 20 '13 at 22:46
  • Both relatively recent heads of gcc (4.9.0 20131031 (experimental)) and clang (version 3.4 (trunk 193991)) compile the code consisting of my declarations without your code (fixed by adding semicolons and removing `...`) without problems. Clang complains about a mismatch between `struct` and `class` for `Bar`, however. – Dietmar Kühl Nov 20 '13 at 22:53
5

Another way to use forward declare is to replace using with the class inheritance:

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

Of course, now FooBar is not the same thing as Foo<Bar>. For instance, you need to inherit possibly existente constructors via using Foo<Bar>::Foo, but as a profit you can use easy forward declare as usual. Just:

namespace fancy {
    class FooBar;
}
αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71
4

If your using declaration is too large (a lot of template parameters, which on their turn are also defined by a using statement), you could also add a dummy forward struct that has the using type as a dependent type:

    namespace fancy {

        struct Bar {
            ...
        }

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

        using FooBar = Foo<Bar>;

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

Then in your place where you want to forward 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);

Some disadvantages of this approach are

  • Using typename to disambiguate the dependent type.
  • Extra indirection for your type, some compilers could have problems when reporting errors.
  • Changing to this approach might need quite a lot of changes to your code (changing every occurence of FooBar with typename FooBarFw::type)

Therefore, I advise to apply this technique only when you are certain what you are doing.

Simon Marynissen
  • 223
  • 2
  • 10
  • This does not work here (after fixing the obvious syntax errors), https://godbolt.org/z/fbPMzcjjW : error: invalid use of incomplete type 'class fancy::FooBarFwd' – smilingthax Aug 13 '23 at 11:32