I'm writing some c++ code that makes use of std::string.
I wanted to see how to code is written, so I went into the source code. (ctrl + left click).
I noticed, that there are macros everywhere.
The code even ends with:
_STD_END
// Corresponds to: #define _STD_END }
I get why macros are useful, and I use them for my own Log.hpp file, but I don't understand why anyone would use macros such as _STD_END instead of just writing }.
Just to clear up, my question is why he author of std::string, P.J. Plauger, decided to use macros in this way, and if I also should?
That’s the Dinkumware library, which Microsoft licenses (although they've recently taken over full maintenance of their version). The _STD_BEGIN and _STD_END macros are used for customizing the std namespace. Some compilers don't (didn't?) support namespaces; for those compilers, the macro expansions are empty. Some compilers need some indirection, and those macros expand into directives that put the code into an implementor-specific namespace (i.e., a namespace whose name begins with an underscore followed by a capital letter), which may or may not be complemented by a using-directive to pull the contents of that namespace into std. And in many cases they expand into the obvious, ordinary namespace std { and }, respectively.
In short, they're about configurability for a multi-platform library implementation.
I worked for Dinkumware for quite a few years, so I have first-hand knowledge.
Related
I am using VS Code. All the following description happens on VS Code env.
I got one header with namespace "Loki" defined which is called "Typelist.h"
I am trying to use a struct inside this namespace defined in this header.
I did:
# define LOKI_TYPELIST_1(T1) ::Loki::TypeList<T1, ::Loki::NullType>
# define LOKI_TYPELIST_2(T1, T2) ::Loki::TypeList<T1, LOKI_TYPELIST_1(T2)>
Normally, I think it should give me intellisense when I am trying to type ::Loki::[Something from namespace Loki], but it doesn't show me anything.
Even, when I am trying to use LOKI_TYPELIST_1 when I define LOKI_TYPELIST_2, it doesn't work either.
What's going on here? Why doesn't the vscode-cpptools extension provide intellisense for namespaced declarations inside macro definitions?
P.S. I did include "Typelist.h" in my current header.
As far as I know, the vscode-cpptools doesn't provide intellisense inside macro definitions.
This is actually fairly reasonable. What a macro definition really means when the macro gets used is often highly dependent on context where it is used. After all... isn't one of the main features of macros?
Take for an (unrealistic, toy) example: #define FOO std::. Let's say I expect to see identifiers for things declared inside the global std namespace when I trigger VS Code to provide suggestions there. Who's to say some lunatic won't redefine what std is and then use FOO?
Granted, if it were instead #define FOO ::std::, our imaginary lunatic is out of luck, but I'd wager this is a case of "It's too much work to distinguish between what is guaranteeable as known inside a macro body, so let's just not provide intellisense there."
Here's more (and probably better) food for thought: How would intellisense know what is declared inside the std namespace at the point of the macro usage? That would depend on what standard headers have been included and what forward declarations have been made before the point of the macro usage. At one usage site, I might have included <string>, and at another, not have included it. Etc. A macro can be used in multiple places. How do you give intellisense for something that can have different valid suggestions depending on where it is used?
Even with such a small example (and there are many varying others), there are already two challenges that make this unduly difficult for the vscode-cpptools extension to provide good suggestions/autocomplete for.
Granted- the vscode-cpptools extension can and will show problem highlighting at/inside the macro if any usage of that macro has problems, because it uses compiler diagnostic messages to find the "site" of the problem, and most compilers will report the specific macro line and column where the problem is happening in their diagnostic messages (in addition to the line and column of where the macro is being used).
I tried to compile this:
enum class conditional_operator { plus, or, not };
But apparently GCC (4.6) thinks these are special, while I can't find a standard that says they are (neither C++0x n3290 or C99 n2794). I'm compiling with g++ -pedantic -std=c++0x. Is this a compiler convenience? How do I turn it off? Shouldn't -std=c++0x turn this "feature" off?
PS: Hmmm, apparently, MarkDown code formatting thinks so too...
Look at 2.5. They are alternative tokens for || and !.
There is a bunch of other alternative tokens BTW.
Edit: The rationale for their inclusion is the same as the one of trigraphs: allow the use of non ASCII character sets. The committee has tried to get rid of them (at least of trigraphs, I don't remember for alternative tokens), and has met opposition of people (mostly IBM mainframe users) which are using them.
Edit for completeness: as other have make the remarks, plus isn't in that class and should not be a problem unless you are using namespace std.
These are actually defined as alternative tokens (and reserved) oddly enough, as alternative representations for operators. I believe this was originally to aid people who were using keyboards which made the relevant symbols hard to produce, although this seems a pretty poor reason to add extra keywords to the language :(
There may be a GCC compiler option to disable them, but I'm not sure.
(As mentioned in comments, plus should be okay unless you're using the std namespace.)
or and not are alternative representations of || and ! respectively. You can't turn them off and you can't use these tokens for anything else, they are part of the language (current C++, not even just C++0x). ( See ISO/IEC 14882:2003 2.5 [lex.digraph] and 2.11 [lex.key] / 2. )
You should be safe with plus unless you use using namespace std; or using std::plus;.
The Standard lists keywords in 2.11. There's also a list of alternative representations separate from the keyword list that is reserved and can't be used otherwise, but aren't keywords. and and or are on that list. Section 17.4.3 describes restrictions on programs that use libraries, and 17.4.3.1.3 describes that names declared with external linkage in a header are reserved both in std:: and the global namespace.
In other words, you don't have to go to C++0x to have those problems. and and or are already reserved, and header <functional> contains plus as a templated struct type, and plus is therefore off-limits if <functional> is directly or indirectly #included.
I'm not sure dumping that much stuff into the global namespace was really wise, but that's what the standard says.
It is an year 1995 amendment to the C90 standard. Probably a compiler may choose on how to behave on this. GCC probably includes the header as part of the standard library. With microsoft it doesn't and you have to include the iso646.h.
Here is a link to wikipedia regarding this.
Boost's C99 stdint implementation is awfully handy. One thing bugs me, though. They dump all of their typedefs into the boost namespace. This leaves me with three choices when using this facility:
Use "using namespace boost"
Use "using boost::[u]<type><width>_t"
Explicitly refer to the target type with the boost:: prefix; e.g., boost::uint32_t foo = 0;
Option № 1 kind of defeats the point of namespaces. Even if used within local scope (e.g., within a function), things like function arguments still have to be prefixed like option № 3.
Option № 2 is better, but there are a bunch of these types, so it can get noisy.
Option № 3 adds an extreme level of noise; the boost:: prefix is often ≥ to the length of the type in question.
My question is: What would be the most elegant way to bring all of these types into the global namespace? Should I just write a wrapper around boost/cstdint.hpp that utilizes option № 2 and be done with it?
Also, wrapping the header like so didn't work on VC++ 10 (problems with standard library headers):
namespace Foo
{
#include <boost/cstdint.hpp>
namespace boost_alias = boost;
}
using namespace Foo::boost_alias;
EDIT: I guess another option is to use the preprocessor to make it work on VC 10? Taking the snippet above:
#ifndef FOO_HPP_INCLUDED
#define FOO_HPP_INCLUDED
#if _MSC_VER >= 1600 /*VC++ 10*/ || defined USE_NATIVE_STDINT_HEADER
#include <stdint.h>
#else
namespace cstdint_wrapper
{
#include <boost/cstdint.hpp>
namespace boost_alias = boost;
}
using namespace cstdint_wrapper::boost_alias;
#endif
#endif
Less work, I guess?
I just use C99's stdint.h (it's actually now in VS 2010). For the versions of Visual C/C++ that don't include it, I use a public domain version from MinGW that I modified to work with VC6 (from when I had to work in VC6):
http://snipplr.com/view/18199/stdinth/
There are a couple other options you might consider in this SO question: C99 stdint.h header and MS Visual Studio
If you'd like to continue using boost/cstdint.hpp, I'd say that the suggestion of implementing a wrapper header that brings the types into the global namespace would be the way to go.
Does boost/cstdint.hpp provide anything I should know about that isn't in stdint.h?
Your idea of writing a wrapper header that implements option 2 is definitely the better of those three options.
What I'd suggest, though, is a slight variant: Put those using declarations within another namespace, such as cstdint or something; then, you have the option if putting using cstdint; in your own code or explicitly specifying cstdint:: on the particular uses.
If you included directly the file you will be forced to prefix it with std::. So the question is, which option would you take in this case. What would you do with the other types introduced by Boost? Would you prefix them with boost:: or not?
The fist one is clearly a bad option.
You can implement option two using your my_cstdint.hpp file
#include <boost/cstdint.hpp>
using boost::uint32_t;
...
and include my_cstdint.hpp in your application. But in my opinion it is a bad idea to add new symbols on the root namespace, you can get more conflicts as the types can be already defined by for example the stdint.h C file.
Even if the third option use a lot of characters, namespaces are there for this purpose. boost::uint32_t will be defined to the correct type depending on your toolset, so just use it, as you would use std::uint32_t.
I personally always use option 3. If things are too long, then you can use typedefs to reduce the amount of code.
In standard library, I found that namespace std is declared as a macro.
#define _STD_BEGIN namespace std {
#define _STD_END }
Is this a best practice when using namespaces?
The macro is declared in Microsoft Visual Studio 9.0\VC\include\yvals.h. But I couldn't find the STL files including this. If it is not included, how it can be used?
Any thoughts..?
Probably not a best practice as it can be difficult to read compared to a vanilla namespace declaration. That said, remember rules don't always apply universally, and I'm sure there is some scenario where a macro might clean things up considerably.
"But I couldn't find the STL files including this. If it is not included, how it can be used?".
All files that use this macro include yvals.h somehow. For example <vector> includes <memory>, which includes <iterator>, which includes <xutility>, which includes <climits>, which includes <yvals.h>. The chain may be deep, but it does include it it some point.
And I want to clarify, this only applies to this particular implementation of the standard library; this is in no way standardized.
In general No. The macros were probably used at the time when namespaces were not implemented by some compilers, or for compatibity with specific platforms.
No idea. The file would probably be included by some other file that was included into the STL file.
One approach that I saw in a library that I recently used was:
BEGIN_NAMESPACE_XXX()
where XXX is the number of namespace levels for example:
BEGIN_NAMESPACE_3(ns1, ns1, ns3)
would take three arguments and expand to
namespace ns1 {
namespace ns2 {
namespace ns2 {
and a matching END_NAMESPACE_3 would expand to
}
}
}
(I have added the newlines and indentation for clarity's sake only)
I imagine the only reason to do this is if you want to make it easy to change the namespace used by your application / library, or disable namespaces altogether for compatibility reasons.
I could see doing this for the C libraries that are included in C++ by reference (eg., the header that C calls string.h and that C++ calls cstring). In that case, the macro definition would depend on an #ifdef _c_plus_plus.
I wouldn't do it in general. I can't think of any compiler worth using that doesn't support namespaces, exceptions, templates or other "modern" C++ features (modern is in quotes because these features were added in the mid to late '90s). In fact, by my definition, compilers are only worth using if they offer good support for their respective language. This isn't a language issue; it's a simple case of "if I chose language X, I'd prefer to use it as it exists today, not as it existed a decade or two ago." I've never understood why some projects spend time trying to support pre-ANSI C compilers, for instance.
The C++ Programming Language : Special Edition states on page 431 that...
For every header < X.h > defining part of the C standard library in the global namespace and also in namespace std, there is a header < cX > defining the same names in the std namespace only.
However, when I use C headers in the < cX > style, I don't need to qualify the namespace. For example...
#include <cmath>
void f() {
double var = sqrt( 17 );
}
This would compile fine. Even though the book says that using the < cX > header defines names in the std namespace only, you are allowed to use those names without qualifying the namespace. What am I missing here?
P.S. Using the GNU.GCC compiler
Stephan T. Lavavej, a member of the MSVC team, addresses the reality of this situation (and some of the refinements to the standard) in this comment on one of his blog postings (http://blogs.msdn.com/vcblog/archive/2008/08/28/the-mallocator.aspx#8904359):
> also, <cstddef>, <cstdlib>, and std::size_t etc should be used!
I used to be very careful about that. C++98 had a splendid dream wherein <cfoo> would declare everything within namespace std, and <foo.h> would include <cfoo> and then drag everything into the global namespace with using-declarations. (This is D.5 [depr.c.headers].)
This was ignored by lots of implementers (some of which had very little control over the C Standard Library headers). So, C++0x has been changed to match reality. As of the N2723 Working Paper, http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2723.pdf , now <cfoo> is guaranteed to declare everything within namespace std, and may or may not declare things within the global namespace. <foo.h> is the opposite: it is guaranteed to declare everything within the global namespace, and may or may not declare things within namespace std.
In reality and in C++0x, including <cfoo> is no safeguard against everything getting declared in the global namespace anyways. That's why I'm ceasing to bother with <cfoo>.
This was Library Issue 456, http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456 .
(C++0x still deprecates the <foo.h> headers from the C Standard Library, which is hilarious.)
I'm in 100% agreement with Lavavej, except I never tried to be very careful about using the <cfoo> style headers even when I first started using C++ - the standard C ones were just too ingrained - and there was never any real world problem using them (and apparently there was never any real world benefit to using the <cfoo> style headers).
The rule for the C libraries differs from C++ libraries for namespaces
gcc interprets the standard in Gcc docs as
The standard specifies that if one includes the C-style header (<math.h> in this case), the symbols will be available in the global namespace and perhaps in namespace std:: (but this is no longer a firm requirement.) One the other hand, including the C++-style header (<cmath>) guarantees that the entities will be found in namespace std and perhaps in the global namespace.
In the draft C0X++ spec it says in section 17.6.2.3 Headers
It is unspecified whether these names are first declared within the global namespace scope and are then injected
into namespace std by explicit using-declarations
It's hard to fix this without implementing the C library twice. See DR 456, which basically proposes giving up on the problem.
Why do you say "This would compile fine" when it violates the Standard? Who allows you to use those names without qualifying the namespace? Have you tested this on a particular implementation and found that it works?
I strongly advise against using some particular non-standard feature because it happens to work on your compiler of choice. Such things break easily, perhaps with a later version of the same compiler.
You are probably missing using a standards-conformant compiler (or the one you use is configured to be compatible with pre-standard code).