简体   繁体   中英

The order in which to declare objects and using typedef in C++

Consider a class A, STL container B and a binary predicate C for the container.

Container B is used in class A. But class A is also used in the binary predicate C.

struct C{
  bool operator()(A const &a, A const &b){
    return a.compare_variable < b.compare_variable;
  }
};

We need this predicate in order to define the container, which uses it to order its elements.

Because the container declaration becomes rather long, I used typedef to simplify the declaration.

typedef B<A, vector<A>, C> type;

Finally, my goal is to declare the container B ---whose declaration is abbreviated to "type" --- inside the class A. Namely, as a static public member variable.

class A{
  public:
  type container1, container2;
};

What is the right order is which to declare A, B and C?

I tried the following variations in the order:

  • first declaring the class A, then the struct C and at last the typedef, I get the error that container1, container2 do not name a type --- type did not exist at the time of the class declaration;

  • first the typedef: loads of errors --- both the class and struct are not defined yet;

  • first declaring the class, with the typedef in the public: section the the struct: an error saying that the third template argument (C) is invalid --- it has not been defined yet;
  • first declaring the struct: error saying the the class is not defined yet.

Is the method that I use unnecessarily cumbersome and does there exist a more elegant solution?

Important caveat : Standard library containers like std::vector technically do not support incomplete types . Instantiating them with an incomplete type is undefined behavior. The type A is incomplete in the definition of A , which means that you can't reliably use, for example, a member of type std::vector<A> in the definition of A . Thus, you'd want to use something like one of Boost's containers that has guaranteed support for incomplete types.

The below discussion assumes that B and vector support instantiation with incomplete types. If they don't, it would be impossible to do what you are trying to do.


First, figure out the dependencies:

struct C {
  bool operator()(A const &a, A const &b){
    return a.compare_variable < b.compare_variable;
  }
};

Defining C itself, including declaring C::operator() , only requires A to be forward-declared. However, defining C::operator() requires the full definition of A , because the function body references a member of A .

typedef B<A, vector<A>, C> type;

Defining type merely requires A , vector , B , and C to be forward-declared. A typedef by itself doesn't trigger instantiation of the templates.

class A{
public:
    type container1, container2;
};

This triggers the instantiation of B<A, vector<A>, C> , requiring the full definition of B . Containers are likely to also require C , the comparator, to be a complete type, since they need to store a copy of it.

So, in short:

  • Defining C requires a forward declaration of A . Defining C::operator() requires the full definition of A .
  • Defining type requires the forward declaration of A , B and C .
  • Defining A requires the full definition of B and C .

Once you've sorted out the dependencies, you can write the code. Assuming B is defined by including the appropriate header:

class A;     // Forward declare A for C's definition
struct C {
  bool operator()(A const &a, A const &b);
};

typedef B<A, vector<A>, C> type;

class A{
public:
    type container1, container2;
};

inline bool C::operator()(A const &a, A const &b){
  return a.compare_variable < b.compare_variable;
}

Note that you need to actually make a compare_variable member in A, obviously.

So you want something like this?

class A {
  struct C{
    bool operator()(A const &, A const &);
  };
  typedef B<A, vector<A>, C> type;
  type c1, c2;

public:
  int compare_variable; // ?
};
// the definition below should either go in a .cpp file,
// or you should mark it inline
bool A::C::operator()(A const &x, A const &y) {
  return x.compare_variable < y.compare_variable;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM