7

I think following code should generate an error:

#include <iostream>
#include <string>

static void pr(const std::string &aStr)
{
    std::cout << aStr << "\n";
}

int main(void)
{
    const char *a = "Hellu";

    pr(a);

    return 0;
}

But gcc 4.1.2 compiles it successuflly.

Is it that the constructor of std::string get in the way, creating an instance of std::string?

I believe it shouldn't, because reference is merely an alias to a variable (in this case, there is no variable of type std::string that the reference is referring to).

Is anybody out there to explain why the code compiles successfully?

Thanks in advance.

Young-hwi
  • 607
  • 7
  • 14

2 Answers2

13

Yes, given a reference to a constant, the compiler can/will synthesize a temporary (in this case of type std::string) and bind the reference to that temporary.

If the reference was not to a const object, however, that wouldn't work -- only a reference to const can bind to a temporary object like that (though at least widely used compiler allows a non-const reference to bind to a reference as well).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Interessting facts. One is learning everyday ;). I didnt get your second sentence right though. Do you mean if the function header would be `void pr(std::string &aStr)` a construction of a temporary (by implying) is not possible by the standart? – Sebastian Hoffmann Jul 02 '12 at 07:04
  • @Paranaix: Correct -- `pr(std::string &)` would not be able to accept a temporary object. – Jerry Coffin Jul 02 '12 at 07:07
  • @JerryCoffin, then, is there any way to keep the compiler from making a temp instance? – Young-hwi Jul 02 '12 at 07:16
  • @orchistro You want to call the operator<< method of the temporary object, don't you? – harper Jul 02 '12 at 07:29
  • @orchistro, just curious: why do you want to prevent the implicit conversion? – Frederick Roth Jul 02 '12 at 07:29
  • @orchistro What do you want to happen instead of the temporary? Compile error? If you provide another function overload that doesn't require creation a temporary, that will be called instead. – Potatoswatter Jul 02 '12 at 07:37
  • I just want compiler to generate an error, but there seems to be no way to do that (is case of gcc), I'll just live with that. – Young-hwi Jul 02 '12 at 08:11
  • @FrederickRoch, I was refactoring legacy code which have many funcs with args of `const char*` where they call `strlen()`. I thought the needless loops will disappear by changing them to accept `const string&` instead of `const char*`. And this problem popped up. The callers will still be handing `const char*` over to the legacy funcs I already have modified to accept `const string&`. I thought the compiler would generate error for func type mismatch so that I could take care of callers, which turned out to be false. Now, I am stuck with callers still calling legacy funcs with `cosnt char*`. – Young-hwi Jul 02 '12 at 08:33
  • 1
    @orchistro: It seems to me that the obvious answer would be to temporarily modify the functions to take references to non-const `std::string`, so the compiler will reject anything that tries to pass a `char *` or `char const *`. I'd probably use a typedef to make it relatively quick and easy to switch the argument type. – Jerry Coffin Jul 02 '12 at 14:22
  • @JerryCoffin, It is a brilliant idea! Unfortunately, I've already done it in stupid way, thanks. – Young-hwi Jul 04 '12 at 07:39
  • @SebastianHoffmann FYI, I found https://stackoverflow.com/a/34527269/1085251. It explains why 'non-const' references are not allowed to be bound to temporaries. Hope it helps. – Young-hwi Feb 08 '23 at 04:18
3

What you encounter is implicit conversion.

Here is a quote from the C++ Standard (SC22-N-4411.pdf)

1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

So the compiler just works as intended and calls the std::string constructor you mentioned.

Frederick Roth
  • 2,748
  • 4
  • 28
  • 42