16

I am a C++ beginner, so sorry if the question is too basic.

I have tried to collect the string constrcturs and try all them out (to remember them).

string strA();          // string(); empty string // incorrect
string strB("Hello");   // string( const char* str)
string strC("Hello",3); // string( const char* str, size_type length)
string strD(2,'c');     // string( size_type lenght, const char &c)
string strE(strB);      // string( const string& s)

cout << strA << endl;
cout << strB << endl;
cout << strC << endl;
cout << strD << endl;
cout << strE << endl;

All of them works except for the strA. It prints "1". Why? Whats the type of the strA in this case? How can I check the type of stuff when I am unsure?

I have noticed that the correct way is this (which by the way seems to be inconsistent with the other constructors, sometimes parens sometimes no parens):

string strA;

ps: question in bold, usual irrelevant answers will be downvoted.

George
  • 15,241
  • 22
  • 66
  • 83

7 Answers7

32

This is a very popular gotcha. C++ grammar is ambiguous. One of the rules to resolve ambiguities is "if something looks like declaration it is a declaration". In this case instead of defining a variable you declared a function prototype.

string strA();

is equivalent to

string strA(void);

a prototype of a no-arg function which returns string.

If you wish to explicitly call no-arg constructor try this:

string strA=string();

It isn't fully equivalent - it means 'create a temporary string using no-arg constructor and then copy it to initialize variable strA', but the compiler is allowed to optimize it and omit copying.

EDIT: Here is an appropriate item in C++ FAQ Lite

Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
14

It considers

string strA();

as a function declaration.

For default constructor use:

string strA;
Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
6

In C++, as in C, there is a rule that says that anything that looks like a declarartion will be treated as a declaration.

string strA();

looks like a function declaration, so it is treated as one. You need:

string strA;
4

I don't think that in this case, the rule "if it could be a declaration, it's taken to be a declaration" applies. Since in the following, both things are declarations

string a;
string a();

The one is the declaration of an object, and the other is the declaration of a function. The rule applies in other cases. For example, in this case:

string a(string());

In that case, string() can mean two things.

  • Declaration of an unnamed function parameter
  • Expression creating a default constructed string

The fule applies here, and string() is taken to mean the same as the following, named parameter (names are irrelevant in parameters when declaring a function)

string a(string im_not_relevant());

If a function takes as parameter an array or another function, that parameter decays into a pointer. In case of a function parameter, to a pointer to the function. Thus, it is equivalent to the following, which may look more familiar

string a(string (*im_not_relevant)());

But in your case, it's rather the syntax that's getting into the way. It's saying that the following is a function declaration. It can never be the declaration of an object (even though that was probably intended by the programmer!)

string a();

So there is no ambiguity in this context in the first place, and thus it declares a function. Since string has a user defined constructor, you can just omit the parentheses, and the effect remains the same as what was intended.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
3

It prints 1 because pointers to functions are always converted to numeric as true.

laalto
  • 150,114
  • 66
  • 286
  • 303
  • 5
    Only if the pointer to function is non-null. Anyway, a pointer to function should point to its definition, and that's missing here. This shouldn't have linked. – MSalters May 29 '09 at 14:21
2

tkopec is right on why it doesn't work. To answer your second question, here's how you check the type:

template<typename TEST> void Error_() {
   TEST* MakeError = 1;
}

By calling Error_(StrA); you will get a compile error, and your compiler will probably tell you that it happened in Error_< std::basic_string<char, std::allocator<char> > (*)(void)>(std::basic_string<char, std::allocator<char> > (*)(void)) Now, std::basic_string > is just std::string, so this really means Error_< std::string (*)(void)> (std::string (*)(void)). The part between '<>' is repeated between '()', and that's the sype of strA. In this case, std::string (*)(void).

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • Type of strA is a function. std::string(void) . It's not a function pointer. He would have to declare it as string (*strA)(); if he wanted it to be a function pointer. I probably know what you meant, but your last sentences sound like you say it's a function pointer. – Johannes Schaub - litb May 29 '09 at 15:00
1

Compiler interprets string strA() as a function prototype of a function which takes void arguments and returns an object of string type. If you want to create a empty string object use string strA; (without paranthesis)

Naveen
  • 74,600
  • 47
  • 176
  • 233