Way to pre-declare standard templated class types?

Started by
11 comments, last by wintertime 11 years, 1 month ago

For compile time optimizations, I'd like a way to pre-declare std::string, and some common container classes I use alot. Specifically, std::vector<std::string>, and to a lesser extant, std::map<std::string, std::string>.

Since I can't go like this:

namespace std { class string; }

(Because std::string is really the templated type std::basic_string<char>)

I was wondering what you gentlemen think about something like this:

class MyString; //Pre-declaration in the headers that need it.
 
void myFunc(MyString &myString);
 
//Later, the actual definition:
class MyString : public std::string { };

Since my entire code-base would follow this usage of std::string and std::vector<std::string>, the direct conversion of std::string into MyString wouldn't be a problem. Though, if it was, I could make MyString have an explicit std::string constructor and implicit std::string castability, and when C++11's constructor inheritance is added to MinGW (in the upcoming 4.8), do that.

On a scale of 1-10, how much does this make you want to hang me? laugh.png

Are there any ramifications or side-effects I'm not realizing, in doing this?

Advertisement

I'm sure you know you these standard classes don't have virtual destructors, and I'm sure you know this means you can't delete a polymorphic pointer to your MyString. People often bring this up as a huge issue when it comes to inheriting from standard classes, and while it's entirely valid, I don't think it's a realistic problem for any half-sane programmer. So in short, there isn't a real technical problem.

However, I want to hang you on a scale of about 6. Reducing build times is great and all, but I'd personally rather have longer build times than using custom classes simply for the sake of forward declaration.

Particularly, MyString uses camel casing, unlike any of its member functions. I hate that inconsistency. And sure, you can provide functions so I can use std::string instead of MyString, but still, I'd personally prefer MyString to serve more of a purpose than simply forward declaration. If that's its only purpose, I'd prefer the longer build times and not use it.

[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

Usually precompiled headers are brought up a lot with template heavy code to reduce compile times. Is that not an option or are build times still too long?

f@dzhttp://festini.device-zero.de

Why not just forward declare std::string?

namespace std
{
template < typename T > struct char_traits;
template < typename T > class allocator;
template
<
    typename charT,
    typename traits,
    typename Alloc
> class basic_string;

typedef basic_string<char, char_traits<char>, allocator<char> > string;
}
 
// type now valid
const std::string* ptr = 0;

// before including the actual header files
#include <string>

the code above was tested with gcc 4.42. Your implementation may vary

Doing so is non-portable. Adding a declaration to namespace std is undefined behavior according to the C++ standard, which includes forward declarations of standard library classes.

Are there any ramifications or side-effects I'm not realizing, in doing this?

What on earth are you trying to accomplish with this ungodly hack?

- If you are worried about compile times, a pre-compiled header should fix that.

- If you are worried about typing, a typedef should fix that.

- If you are trying to solve circular dependencies... SAY WHAT?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I'm not worried about typing, I prefer names like 'std::string' over names like 'string'.

And it's definitely not circular dependencies. laugh.png

It's just compile times - I've tried pre-compiled headers, several times, but every time so far, the compiler (MinGW) would sporadically crash halfway through the build (the compiler itself, not the compiled code), and it'd take down the IDE (QtCreator) with it. QtCreator has support for pre-compiled headers, and I followed the QtCreator documentation for pre-compiled headers with MinGW. It just was unstable. When it worked (every 2 out of 3 compiles), it greatly reduced compile times. But when it failed, I had to End Task mingw32-make and then restart my IDE - which was very upsetting to my workflow.

I hadn't considered the lack of virtual destructors actually, but I hadn't intended to use these polymorphically.

I didn't really want to rename std::string anyway - it makes it harder for others to read the code. I do have tons (several dozen) of std::string helper functions in a separate namespace (String::blah()), but as much as I'd like them in some String class for convenience, it'd make the class too much of a monolith, so they're probably better off as standalone functions.

I'll try RobTheBloke's method - even if it's non-standard, if it works with MinGW and GCC on most platforms, I'd be fine with it. Is the worse case scenario (on sane compilers), a failure to compile or is it likely that something harder to detect would result? Maybe accidentally declaring new 'standard' classes (but without definitions) by mistake?

I wonder if GCC has a non-standard built-in pre-declaration header somewhere that it uses internally - I'll look around.

the compiler (MinGW)

I think I found your problem blink.png

But in all seriousness, I assume you are using a recent (4.7.2) build of GCC?

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Yep:

g++ (Built by MinGW-builds project) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.

Doing so is non-portable.

The same is also true of #pragma once, un-named unions/structs, SIMD optimisations, fread/fwrite, graphics API's, sound API's, input API's, wide strings, C++ 0x, C++ 11, GUI code, and more or less everything that most game developers use on a daily basis. This is a game developer forum, not comp.lang.c++. If you want program truly portable games, you're choices are: text adventures, and text adventures. If you have any aspirations beyond that, well you're just going to have to accept that your codebase will contain a number of platform specific headers. Your compiler may vary, as will the implementation of the standard library, hence the caveat I posted above.

Adding a declaration to namespace std is undefined behavior according to the C++ standard, which includes forward declarations of standard library classes.

Yes, technically speaking I could write a compiler in which the std lib is implemented as intrinsics, rather than C++ which is treated as a typical library. I doubt you would use it, and I doubt anyone else would either (me included). If the standard lib provided with your compiler is written in C++, it follows the rules of C++. Since forward declarations are legal in C++, it will obey those rules. Or do you disagree?

Is the worse case scenario (on sane compilers), a failure to compile or is it likely that something harder to detect would result?

Failure to compile is the worst that can happen. Annoying, but fixable.

I hadn't considered the lack of virtual destructors actually, but I hadn't intended to use these polymorphically.

If all you're doing data wise is this:

struct String : public std::string
{
   int pod_data_only;
};

there is no problem. If you're doing this:

struct String : public std::string
{
   std::vector< std::map< std::string, std::vector<int> > > dynamic_data;
};

Then be afraid! be very afraid!

- If you are worried about compile times, a pre-compiled header should fix that.

Not always an option. You need a compiler that supports them (PS3? Wii?).

- If you are trying to solve circular dependencies... SAY WHAT?

It happens, especially when working in large teams. It shouldn't happen, and there is usually a way to fix them 'properly', but when deadlines are tight, it's usually better to get it out of the door no matter what, than refactor vasts swathes of code (and go through another round of QA/bug-fixing/delayed release).

This topic is closed to new replies.

Advertisement