The #include directive may not belong there, but what triggers the error is just using the string variable in defining my structure. It just seems to me that there has to be a way to use non-primitive data-types in your header files, but I'm not getting it right, obviously.

Just as point of info, this goes with ch. 9, ex. 2 in Prata, C++ Primer Plus.

07-31-2009

tabstop

C++ has never had a string. It does have a std::string, however.

07-31-2009

Aisthesis

While it may be stating the obvious, I should perhaps add that this is the complete file golf.h, which is the prototype file for golf.cpp, where the functions are defined. And both then link to another file (called pe9-2.cpp just because of exercise sequence, but name doesn't matter).

I suppose I should also have created an include guard, but it shouldn't really matter with respect to the current issue.

07-31-2009

Aisthesis

Ah, interesting. So does that mean that my code should work if I do either of the following:

1) put in "using std::string" at the top and leaving out the #include <string> at the top.

2) leave out the #include <string> (which just looks wrong to me, although it doesn't seem to be causing any error--but I'm not convinced that it's doing anything good either) and just substitute "std::string" in each instance where I've used the word "string".

07-31-2009

Aisthesis

yep, throwing out the include and putting in "using std::string;" at the top made it compile.

Haven't tested it for doing what I want, but I think it probably will.

Thanks!

07-31-2009

brewbuck

Quote:

Originally Posted by Aisthesis

yep, throwing out the include and putting in "using std::string;" at the top made it compile.

Haven't tested it for doing what I want, but I think it probably will.

Thanks!

Never, ever, ever, EVER put a using directive in a header file. NEVER.

07-31-2009

Aisthesis

well, that's a using declaration, right? So, in this specific case, it just means that in any file linked to that header file, "string" is interpreted as "std::string".

I'm not seeing exactly how that leads to such horrors in the long-run... ??

Prata does say to "avoid" using DIRECTIVES in header files, but even there, he doesn't make it sound quite as taboo as you are suggesting...

07-31-2009

brewbuck

Quote:

Originally Posted by Aisthesis

well, that's a using declaration, right? So, in this specific case, it just means that in any file linked to that header file, "string" is interpreted as "std::string".

Which means that any file which wants to declare a type called "string" is completely inoperable with that header file. In the worst case, it still compiles, but the type is silently wrong.

07-31-2009

cpjust

1. If you're using std::string in your header, you need to #include <string> in your header. Otherwise your code won't compile if you change the order of your #include statements in your .cpp file.

2. Don't put using directives in header files for the reason brewbuck gave.

08-01-2009

VirtualAce

Quote:

Prata does say to "avoid" using DIRECTIVES in header files, but even there, he doesn't make it sound quite as taboo as you are suggesting...

In large code bases it is extremely taboo. Others who include your header bring in the entire namespace you brought into the header. In a cpp it's perfectly valid to use a using because your implementation file will not be included by anyone else - providing you have at least halfway intelligent programmers on your team. If someone does include your implementation file and it's not a template impl then you can smack them for being stupid.

08-01-2009

Daved

So to sum up:

Code:

#include <string>

struct golf
{std::string fullname;
int handicap;
};

...

08-01-2009

Mario F.

Aisthesis, leave the include declaration as it was initially. That's not the source of your error and it is the right thing to do. You are including a standard library header file that declares the object you need to use. On this case, std::string.

The change you need to make for your initial code to work is to prefix std:: to string. Since the string class is declared inside the namespace std, you need to call it with the std qualifier.

Now, let's assume this bothers you because your golf struct declares a bunch of standard library types and you don't want (for some reason) to write std:: all over the place. That's just fine. You can use a typedef...

It is declared private because this is merely an implementation shorthand. You don't want it to be accessed by users of your class.

Another (probably better) solution is to create your own namespace:

Code:

#include <string>

namespace mine {
using std::string;

struct golf
{
string fullname;
int handicap;
};
}

Probably better because the habit of creating and maintaining our own namespaces is a good thing since it is a powerful tool that allows us to curb name collision or better support the separation of interface and implementation.

In any case here, despite you use a using declaration inside a header file, it is declared inside a namespace you control, and is only local to that namespace.

08-02-2009

Mario F.

This has been bugging me... I don't think I gave a good advise here...

Code:

#include <string>

namespace mine {
using std::string;

struct golf
{
string fullname;
int handicap;
};
}

You really don't want to do this. It's true you are lifting std::string inside a namespace you control. But there can be very real reasons for a user of your namespace to want to do:

Code:

using namespace mine;

At function scope for instance, or when merging your namespace with their own. On the other hand the using declaration is being made at too much of a higher scope. Right at mine::. This isn't correct. You will be exposing std::string too much. Perhaps even to areas of the namespace mine where it isn't necessary or desirable.

Consider the typedef approach the more correct.

Anyone care to comment?

08-02-2009

laserlight

Quote:

Originally Posted by Mario F.

Anyone care to comment?

In C++ Coding Standards, Sutter and Alexandrescu recommend against using directives and using declaration in namespace scope in a header file, and that recommendation includes avoiding what you suggested about a using declaration within a namespace.

As a demonstration, they provide this code snippet, with the critical question in a comment:

Code:

// snippet 1
namespace A {
int f(double);
}

// snippet 2
namesapce B {
using A::f;
void g();
}

// snippet 3
namespace A {
int f(int);
}

// snippet 4
void B::g() {
f(1); // which overload is called?
}

They proceed to comment that:

Quote:

The dangerous thing happening here is that the using declaration takes a snapshot of whatever entities named f in namespace A have been seen by the time the using declaration is encountered. So, from within B, which overloads are visible depends on where these code snippets exist and in what order they are combined. (At this point, your internal "but order dependencies are evil!" klaxon should be blaring.) The second overload, f(int), would be a better match for the call f(1), but f(int) will be invisible to B::g if its declaration comes after the using declaration.

08-02-2009

Mario F.

Yeah. That was my thought too. I couldn't be right.
Thanks for the confirmation.