96

I am trying to use forward declarations in header files to reduce the number of #include used and hence reduce dependencies when users include my header file.

However, I am unable to forward declare where namespaces are used. See example below.

File a.hpp:

#ifndef __A_HPP__
#define __A_HPP__

namespace ns1 {

   class a {
   public:
      a(const char* const msg);

      void talk() const;

   private:
      const char* const msg_;
   };
}

#endif //__A_HPP__

File a.cpp:

#include <iostream>

#include "a.hpp"

using namespace ns1;

a::a(const char* const msg) : msg_(msg) {}

void a::talk() const { 
   std::cout << msg_ << std::endl; 
}

File consumer.hpp:

#ifndef __CONSUMER_HPP__
#define __CONSUMER_HPP__

// How can I forward declare a class which uses a namespace
//doing this below results in error C2653: 'ns1' : is not a class or namespace name
// Works with no namespace or if I use using namespace ns1 in header file
// but I am trying to reduce any dependencies in this header file
class ns1::a;

class consumer
{
public:
   consumer(const char* const text) : a_(text) {}
   void chat() const;

private:
   a& a_;
};

#endif // __CONSUMER_HPP__

Implementation file consumer.cpp:

#include "consumer.hpp"
#include "a.hpp"

consumer::consumer(const char* const text) : a_(text) {}

void consumer::chat() const {
   a_.talk();
}

Test file main.cpp:

#include "consumer.hpp"

int main() {
   consumer c("My message");
   c.chat();
   return 0;
}

UPDATE:

Here is my very contrived working code using the answer below.

File a.hpp:

#ifndef A_HPP__
#define A_HPP__

#include <string>

namespace ns1 {

   class a {
   public:
      void set_message(const std::string& msg);
      void talk() const;

   private:
      std::string msg_;
   };

} //namespace

#endif //A_HPP__

File a.cpp:

#include <iostream>
#include "a.hpp"

void ns1::a::set_message(const std::string& msg) {
    msg_ = msg;
}
void ns1::a::talk() const { 
   std::cout << msg_ << std::endl; 
}

File consumer.hpp:

#ifndef CONSUMER_HPP__
#define CONSUMER_HPP__

namespace ns1
{
   class a;
}

class consumer
{
public:
   consumer(const char* text);
   ~consumer();
   void chat() const;

private:
   ns1::a* a_;
};

#endif // CONSUMER_HPP__

File consumer.cpp:

#include "a.hpp"
#include "consumer.hpp"

consumer::consumer(const char* text) {
   a_ = new ns1::a;
   a_->set_message(text);
}
consumer::~consumer() {
   delete a_;
}
void consumer::chat() const {
   a_->talk();
}

File main.cpp:

#include "consumer.hpp"

int main() {
   consumer c("My message");
   c.chat();
   return 0;
}
3
  • 8
    Don't use names starting with two underscores or an underscore and a capital letter for macros -- these are reserved. stackoverflow.com/questions/17307540/… Commented Sep 25, 2013 at 9:59
  • this is not just a namespace issue. consumer.cpp is aware that there is a class type a, but it is not aware of the specifics. You try to invoke the method a::talk(), which the compiler knows nothing about. You still need to #include "a.hpp" from consumer.cpp so the compiler is aware of the classes full interface. This #include will be internal to the .cpp hence will not be "spread around" through consumer.hpp.
    – Avi Perel
    Commented Sep 25, 2013 at 10:35
  • This question is similar to: Is there a shorter way to forward declare a class in a namespace?. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Sep 10 at 8:47

3 Answers 3

137

To forward declare class type a in a namespace ns1:

namespace ns1
{
    class a;
}

To forward declare a type in multiple level of namespaces:

namespace ns1
{
  namespace ns2
  {
    //....
     namespace nsN
     {
        class a;
     }
    //....    
  }
}

Your are using a a member of consumer which means it needs concrete type, your forward declaration won't work for this case.

4
  • 6
    +1: Its easily 10 years since I wrote C++ in anger but I immediately knew the answer to this, simply re-declare the namespace. I'm quite pleased I remembered that, I've forgotten so much else . . . Commented Sep 25, 2013 at 9:59
  • 3
    @Thomas, I just tried that and got error C3083: 'ns1': the symbol to the left of a '::' must be a type Commented Sep 25, 2013 at 10:04
  • 2
    @Thomas I believe that only works if the namespace already exists. Commented Sep 25, 2013 at 10:13
  • 3
    @Iron Not only that namespace must exist, but the class must be declared in it, in which case there's little point redeclaring the class outside of namespace. Commented Sep 25, 2013 at 10:17
40

For nested namespaces, since C++17, you can do

namespace ns1::ns2::nsN
{
  class a;
}
3
  • 14
    How about just class ns1::ns2::nsN::a? Commented Aug 1, 2020 at 20:48
  • That's a relief, the old form was so long when a class was nestled.
    – pjcard
    Commented Jun 25, 2021 at 10:51
  • 1
    It would definitely be nice, @santahopar, but it isn't valid sytax (yet?). Might be worth proposing for the next C++ standard, either as class ns1::ns2::nsN::a, or as namespace ns1::ns2::nsN::class a, perhaps. Commented Jul 12, 2023 at 16:54
5

Apart to forward-declare the class from within its namespace (as @billz says), remember to either use (prepend) that namespace when referring to the forward-declared class, or add a using clause:

// B.h
namespace Y { class A; } // full declaration of
// class A elsewhere

namespace X {
    using Y::A;   // <------------- [!]
    class B {
        A* a; // Y::A
    };
}

Ref: Namespaces and Forward Class Declarations

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.