Is it possible to forward declare an standard container in a header file? For example, take the following code:
#include <vector>
class Foo
{
private:
std::vector<int> container_;
...
};
I want to be able to do something like this:
namespace std
{
template <typename T> class vector;
}
class Foo
{
private:
std::vector<int> container_;
...
};
Can this be done?
Declaring vector in the std namespace is undefined behavior. So, your code might work, but it also might not, and the compiler is under no obligation to tell you when your attempt won't work. That's a gamble, and I don't know that avoiding the inclusion of a standard C++ header is worth that.
See the following comp.std.c++.moderated discussion:
forward declaring std::vector. Works, but is it legal and standard compliant?
I don't think so because the compiler would have no way of knowing how much space to allocate for the container_ object. At best you could do:
std::vector<int> *container_;
and new it in the constructor, since the compiler knows the size of a pointer.
Apart from what the others said, you may find it useful to know that there is a sanctioned way of forward-declaring iostreams and some related templates: The header <iosfwd>. It would be useful if the standard had more such headers.
Related
I know it's impossible to do
class foo{
foo bar;
};
Because the compiler wouldn't know how much memory to prepare for foo.
But consider:
class A{
B::C* foo;
};
class B{
class C{
};
};
It seems quite reasonable that the compiler would know exactly the size of A no matter the definition of the C. Why isn't this possible then? (Does the standard forbids that explicitly? for what?)
I got a very crude way by-pass the constraint that is to treat foo as a uintptr_t, then reinterpret_cast it back to C, this is just to show that I really don't get the (objective) reason, and I know it's a really really bad practice if used without decent reason.
Finally it turns out to be forbidden by the standard.
One big challenge is following:
class other {};
namespace N {
class foo {
other* p;
};
class other {};
}
Which other* should be considered? Too much of work for compiler. Though we can be explicit by ::other or N::other, it still creates confusion in above case.
TL;DR: That is because the standard dicates the syntax to be so. Unfortunately it's as simple as that.
This is the path I followed:
You open standard e.g. c++11 draft.
You seek section about classes it's section 9. You immediatietly see it has subsection "9.2 Class members". There is whole syntax defined. After some reading you get to member-declarator. The most important part in our context is declarator.
Section 8. Declarators. In p4. you have the syntax for declarator. After going through all the formal definition of the fancy syntaxes supported you will notice that it hinges on id-expression.
This is defined in 5.1.1 Primary Expressions. General ([expr.prim.general]). And it has to be a qualified-id of unqualified-id.
So your question could be rephrased to "Why does the namelookup not work like that?" But that is another question.
FWIW, not much I guess, but it's a design decision. It would need to keep track of all failed resolutions for the compilation unit. Doing lazy check in this context comes with quite far reaching implications.
After the example
class foo{
other* bar;
...
};
class other{
...
}
… which (1) uses an undeclared name, and (2) lacks a crucial semicolon, you ask
” Why isn't this possible then? (Does the standard forbids that explicitly? for what?)
The Holy Standard requires that every name must be declared before it's used.
Note that in a given C++ implementation, even data pointers can be of different sizes (void* is guaranteed to be able to hold any data pointer), not to mention function pointers.
An alternative to declare-before-first-use requirement could be to adopt a default, like with implicit int in the early C days. E.g. the compiler could assume that other was a class type. But that would not be very helpful in general, and it would complicate the language.
However, in this particular case it's possible to combine the necessary minimum declaration of other with its first use:
class foo{
class other* bar;
//...
};
class other{
//...
};
Alternatively you could use an ordinary forward declaration:
class other;
class foo{
other* bar;
//...
};
class other{
//...
};
Just so the compiler knows that other is a class type, and not e.g. a function, or a synonym for char or void (pointers to these types are the largest, if there is any variability in the size of basic raw data pointers).
You then assert:
” The dummy example I posted above may seem have no real meaning. The reason why I want to do without forward declaration is that when you got a nested class, there's no forward declaration that can preserve the encapsulation.
That's wrong.
E.g. this works nicely:
class Foo
{
private:
class Other;
Other* bar;
class Other{};
public:
Foo(): bar( new Other ) {}
};
However, the shortcut with declaration in the first use, class Other* bar;, doesn't work in this case. That's because it effectively would declare Other as a namespace level class instead of a nested one.
I want to write a C-wrapper around an existing C++ codebase. So I need to implement some C-API functions that merely forward their operations to the corresponding C++ methods.
My problem is, I cannot figure out how to implement a forward-defined struct by means of an existing class:
//Foo.hpp
namespace myLib {
struct Foo {
//some meaningful C++ body
};
}
//foo.h
//#ifdef __cplusplus etc. left out
extern "C" {
struct myLib_foo;
myLib_foo* mkfoo();
//etc.
}
//foo.cpp
extern "C" {
#include "Foo.hpp"
#include "foo.h"
typedef myLib_foo myLib::Foo; //this does not work
myLib_foo* mkfoo() { return new myLib::Foo(); }
}
In this situation, the C-API can and shall only work with pointers to myLib::Foo, which obviously works well, if I define myLib_foo as a new struct inside foo.cpp. I guess it also works, if I define a struct myLib_foo somewhere else. Yet, since I want to keep my namespaces manageable, I am searching a way to define myLib_foo to be equivalent to some existing (and completely defined) struct. This, however does not work, since my compiler refuses the code above with "typedef redefinition with different types". Apparently, it distinguishes between type-aliases and structs.
Is there even a way to achieve what I want or does C++ have no means for real type-aliases?
edit:
By the answer below, I figured I can use inheritance plus static_cast:
//foo.cpp
extern "C" {
#include "Foo.hpp"
#include "foo.h"
struct myLib_foo : public myLib::Foo {}; //this does work
myLib_foo* mkfoo() { return static_cast<myLib_foo*>(new myLib::Foo()); }
}
The C code does not ever need a definition of the struct myLib_foo that it sees.
It handles it only through pointers and functions.
On the C++ side a simple implementation is a struct containing a pointer to the "real" object that it represents. You then define it in the ordinary way (in the C++ code), but of course with the name already established for the C code usage.
If you want to avoid even that little inefficiency, to hand out real object pointers to the C code, well then you have essentially two options:
reinterpret_cast, or
static_cast with the not-quite-C struct as a (possibly empty) base class.
But I would go for the simple implementation of myLib_foo as a struct with a pointer to the real one. The KISS principle: Keep It Simple, Stupid*. On second thoughts, to avoid allocation and deallocation issues, and to also avoid a formal dependency on the compiler (even if that would just be academic, a formality), I would go for the static_cast. For thinking about what it all entails, this seems simplest.
*: Oh, the last few times I mentioned this principle on SO, those answers were heavily downvoted. That has also happened when I have (correctly) proposed macros as solutions. I think one should be technically honest and ignore the general SO readership, so I mention it anyway.
I need to implement the following interface
struct mutex;
struct interface
{
//...
mutex& getMutex();
};
Intuition would I could use using mutex = ParticularMutex in my implementation, but gcc tells me otherwise:
error: conflicting declaration ‘using mutex = ’
error: ‘class mutex’ has a previous declaration as ‘class mutex’
I am not defining anything twice, only declaring twice, as usual when forward declaring, so
why doesn't this work?
is there a workaround without modifying interface?
how should interface have been defined? with template <typename mutex>?
It does not work because the forward declaration struct mutex; tells the compiler that mutex is a new type. With using you are then creating a type alias, which means it's not a new type (as promised to the compiler), but an alias to an existing type.
No.
Yes.
What you could do is:
struct mutex : ParticularMutex {
using ParticularMutex::ParticularMutex; // inherit constructors
};
Which does define a type derived from ParticularMutex which is hopefully compatible enough. Of course, this is a new type which might lead to other problems.
In a similar situation (working with JNI abstraction), here is what I do:
JNI-unaware file MyObject.h:
class PlatformObject; // forward declaration
struct MyObject {
int accumulator;
PlatformObject* platformObj;
};
JNI-aware file jniBridge.cpp:
#include <jni.h>
#define PlatformObject _jobject
#include "MyObject.h"
void attach(MyObject& obj, jobject parent) {
obj.platformObj = env->GetObjectField(parent, child_FieldID);
}
void add(MyObject& obj, int k) {
accumulator += k;
env->CallVoidMethod(obj.platformObj, add_MethodID, k);
}
The accepted answer works for add() but not for attach(); extra static_cast is required for the latter.
I believe that in some cases, both approaches have their advantages.
First you're saying that mutex is a specific class type. Then later you're saying "oh wait, mutex isn't its own type, it's really this other type instead". The compiler doesn't know what to do in that case.
Replace struct mutext with the using and it should just work (I'm not totally up to date on C++11 using).
If you want to be able to support multiple mutex implementations, you might want to make the interface a template (or use a mutex abstract interface that virtually decides which mutex implementation to call).
Well, you usually can solve this problem by adding a stub declaration of that ParticularMutex to one of your headers. Something like:
namespace foreignlib {
namespace foreignsublib {
class ParticularMutex;
}
}
And then in your general header:
namespace ourlib {
using mutex = foreignlib::foreignsublib::ParticularMutex;
}
This works fine and parses and compiles fast. The advantage: Whoever reads your general header knows, what this your specific mutex stands for after all. The disadvantage: You cannot write a mutex-agnostic library, where later you can drop in one or the other mutex using the using directive. If you want or need to do that, the C++ Gods want you to use templates instead. But these come at their own price...
I have used forward declarations a lot; they help avoid many #includes, improve compilation time and what not. But what if i want to forward-declare a class in the standard library?
// Prototype of my function - i don't want to include <vector> to declare it!
int DoStuff(const std::vector<int>& thingies);
I have heard it's forbidden/impossible to forward-declare std::vector. Now this answer to an unrelated question suggests to rewrite my code this way:
stuff.h
class VectorOfNumbers; // this class acts like std::vector<int>
int DoStuff(const VectorOfNumbers& thingies);
stuff.cpp
// Implementation, in some other file
#include <vector>
class VectorOfNumbers: public std::vector<int>
{
// Define the constructors - annoying in C++03, easy in C++11
};
int DoStuff(const VectorOfNumbers& thingies)
{
...
}
Now, if i use VectorOfNumbers instead of std::vector<int> in all contexts throughout my project, everything is going to be good, and i don't need to #include <vector> in my header files anymore!
Does this technique have major disadvantages? Can the gain of being able to forward-declare vector outweigh them?
If you ever delete a VectorOfNumbers as a std::vector<int> (and since you used public inheritance this conversion is implicit) you've entered the realm of undefined behavior. This is probably more likely to accidentally happen than one might suspect.
I've never personally noticed significant compilation slowdown from just including vector where needed, but if you really want to isolate the include, use a client API interface that doesn't know about the underlying container type (vector) and pimpl the vector include into a single source file.
The reason I wouldn't do this:
const std::vector<int>& a = a_3rd_party_lib::get_data(); // this type is out of your control
DoStuff(a); // you cannot pass it to this function!
You include <vector> in your header file. The <vector> header will have been built to prevent multiple inclusions, so you just include it everywhere you need it.
This works well for the interface for a class, but not for the implementation. If your class has any vector members you must #include <vector> or the class definition will not compile.
Instead of inheritance, you could use composition:
// Implementation, in some other file
#include <vector>
class VectorOfNumbers
{
public:
std::vector<int>& container;
VectorOfNumbers(std::vector<int>& in_container)
: container(in_container)
{
}
};
int DoStuff(const VectorOfNumbers& thingies)
{
std::sort(thingies.container.begin(), thingies.container.end());
// ...
}
The downside is the extra variable name on every access.
Also, you'd need this implementation to be in a header file included by cpps so they will know what they can do with VectorOfNumbers.
Essentially, just making a wrapper for your vector. This is like a light-weight version of PImpl (we only care about avoiding header dependencies so we don't need the full pointer decoupling). It avoids the issues raised by Mark B and ybungalobill.
But I don't think it's really worth it.
Is there any way to declare a pointer to an incomplete type that will be set by a typedef in the implementation?
Here is exemple of what I want:
#ifndef TEST_H
#define TEST_H
namespace std {
class string; // THIS WON'T WORK!
}
struct Test {
std::string *value;
};
#endif
string is a typedef to basic_string, so the code in the exemple won't work. I could declare an incomplete type of std::basic_string, but thats looks like a workaround.
I know that the compiler won't generate symbols for typedefs, and it could happen that the same name could be used in typedefs for different types in different files. But since a pointer is a pointer (at least to the compiler), it should be possible to do something like that.
EDIT: This is just a minimalist working exemple. In my real problem, I have a Facade which uses a class from a library that only the Facade should need to know (no, it's not std::string, and the library is not stl). I'm not really worried with circular inclusion, but since a lot of files in my project include this Facade (directly or indirectly), I am worried with compile time, so I want to include the library file only in the Facade's implementation file.
No, it's not.
Really, at this point, you're just going to have to #include <string>. It's not harmful because you can't have a circular dependency with string: standard headers don't even know that your headers exist!
A std::string* is usually wrong, anyway.
Forward declaring std::string might look something like this:
namespace std
{
template <class T, class Traits, class Allocator>
class basic_string;
template <class T>
class char_traits;
template <class T>
class allocator;
typedef basic_string<char, char_traits<char>, allocator<char> > string;
}
Example.
(This doesn't attempt to forward declare that basic_string has default template arguments. Since those can only be declared once, I suspect only library authors might have enough control to pull it off.)
As to questioning the usage of std::string*, I guess no-one would allocate them dynamically. However, isn't it valid to want to reference some other string elsewhere (or NULL)?
Declaring stuff in namespace std is (mostly) undefined. The only legal way to refer to a standard library object, function or type is after including a relevant header. 17.4.3.1 says so.