133
#ifndef __TEST__
#define __TEST__

namespace std
{
    template<typename T>
    class list;
}

template<typename T>
void Pop(std::list<T> * l)
{
    while(!l->empty())
        l->pop();
}

#endif

and used that function in my main. I get errors. Of course, I know that there are more template params for std::list (allocator I think). But, that is beside the point. Do I have to know the full template declaration of a template class to be able to forward declare it?

EDIT: I wasn't using a pointer before - it was a reference. I'll try it out with the pointer.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
nakiya
  • 14,063
  • 21
  • 79
  • 118
  • And in the case of list, the second parameter is a default parameter which is `std::allocator` – nakiya Oct 07 '10 at 06:42
  • 2
    one may consider it an oversight that the STL does not contain forward declaration headers. On the other hand, its files are so often included that it would probably not yield any benefit on the compilation time... – Matthieu M. Oct 07 '10 at 07:02
  • 7
    `__TEST__` is a reserved identifier, [don't use it](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – GManNickG Oct 07 '10 at 08:41
  • 1
    possible duplicate of [C++ forward declaration problem](http://stackoverflow.com/questions/2963356/c-forward-declaration-problem) – iammilind Jul 13 '13 at 05:02

4 Answers4

147

The problem is not that you can't forward-declare a template class. Yes, you do need to know all of the template parameters and their defaults to be able to forward-declare it correctly:

namespace std {
  template<class T, class Allocator = std::allocator<T>>
  class list;
}

But to make even such a forward declaration in namespace std is explicitly prohibited by the standard: the only thing you're allowed to put in std is a template specialisation, commonly std::less on a user-defined type. Someone else can cite the relevant text if necessary.

Just #include <list> and don't worry about it.

Oh, incidentally, any name containing double-underscores is reserved for use by the implementation, so you should use something like TEST_H instead of __TEST__. It's not going to generate a warning or an error, but if your program has a clash with an implementation-defined identifier, then it's not guaranteed to compile or run correctly: it's ill-formed. Also prohibited are names beginning with an underscore followed by a capital letter, among others. In general, don't start things with underscores unless you know what magic you're dealing with.

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 4
    Why is it prohibited to forward declare things in `namespace std` btw? – nakiya Oct 07 '10 at 06:46
  • 4
    Check out this answer (http://stackoverflow.com/questions/307343/forward-declare-an-stl-container/307408#307408) and the linked newsgroup discussion. – Jon Purdy Oct 07 '10 at 06:49
  • 7
    Jon / Nakiya, why not use `#pragma once` rather than the #ifdef's. It's supported by most compilers these days. – Mark Ingram Oct 07 '10 at 08:28
  • 11
    @Mark: Because it's `#pragma`, that's why. Though it is an option. – Jon Purdy Oct 07 '10 at 12:33
  • 1
    What's the issue with `#pragma`? – Mark Ingram Oct 07 '10 at 12:49
  • 2
    There are scrillions of duplicates of that question. Just search: http://stackoverflow.com/search?q=pragma+once – Jon Purdy Oct 07 '10 at 14:13
  • correct me if Im wrong but the title says "How to forward declare a template class?" – Simple Fellow Oct 02 '13 at 18:42
  • @SimpleFellow: The title doesn’t correspond so well to the actual question. Still, I’ll add more information in the interest of completeness. – Jon Purdy Oct 02 '13 at 19:49
  • @JonPurdy: Sorry, are you sure that defaults as well are to be specified in the fwd decl? If I do so g++ complains a lot... In my case, however, the defaults were applied not to types, but to template integer parameters... – Andry Nov 15 '13 at 09:32
  • It's worth noting that the reference for the `namespace std` forward declaration prohibition is inconclusive. Basically some guys in a newsgroup claim it is so, it's not really an authoritative source. – Ohad Schneider Dec 06 '16 at 16:20
20

I solved that problem.

I was implementing an OSI Layer (slider window, Level 2) for a network simulation in C++ (Eclipse Juno). I had frames (template <class T>) and its states (state pattern, forward declaration).

The solution is as follows:

In the *.cpp file, you must include the Header file that you forward, i.e.

ifndef STATE_H_
#define STATE_H_
#include <stdlib.h>
#include "Frame.h"

template <class T>
class LinkFrame;

using namespace std;

template <class T>
class State {

  protected:
    LinkFrame<int> *myFrame;

}

Its cpp:

#include "State.h"
#include "Frame.h"
#include  "LinkFrame.h"

template <class T>
bool State<T>::replace(Frame<T> *f){

And... another class.

Littm
  • 4,923
  • 4
  • 30
  • 38
user1638075
  • 317
  • 2
  • 2
  • 35
    Putting any `using namespace` in a header file is a very bad practice because it prevents anyone using that header file from being able to use local names that would otherwise be valid. It basically defeats the entire point of namespaces. – Andy Dent Feb 23 '16 at 06:37
10

Forward declaration should have complete template arguments list specified.

Grozz
  • 8,317
  • 4
  • 38
  • 53
-5

there is a limited alternative you can use

header:

class std_int_vector;

class A{
    std_int_vector* vector;
public:
    A();
    virtual ~A();
};

cpp:

#include "header.h"
#include <vector>
class std_int_vector: public std::vectror<int> {}

A::A() : vector(new std_int_vector()) {}
[...]

not tested in real programs, so expect it to be non-perfect.

Arne
  • 7,921
  • 9
  • 48
  • 66