Why is the Visual C ++ Compiler causing an incorrect overload?

Why is the Visual C ++ Compiler causing the wrong overload here?

I have a subclass of ostream that I use to define a buffer for formatting. Sometimes I want to create a temporary one and immediately insert a line into it with the usual <<operator as follows:

M2Stream() << "the string";

Unfortunately, the program causes the member of the operator <(ostream, void *) to be overloaded, instead of the operator <(ostream, const char *), which is not a member.

I wrote a sample below as a test, where I define my own M2Stream class that reproduces the problem.

I think the problem is that the expression M2Stream () creates a temporary one, and for some reason this makes the compiler prefer void * overloading. But why? This is confirmed by the fact that if I make the first argument to overload the nonmember const M2Stream &, I get ambiguity.

Another strange thing: it causes the desired overload of const char * if I first define a variable of type const char *, and then call it instead of the char string as follows:

const char *s = "char string variable";
M2Stream() << s;  

It is as if the literal string had a different type than the const char * variable! Shouldn't they be the same? And why does the compiler call the void * overload call when I use the char temporary and literal string?

#include "stdafx.h"
#include <iostream>
using namespace std;


class M2Stream
{
public:
    M2Stream &operator<<(void *vp)
    {
        cout << "M2Stream bad operator<<(void *) called with " << (const char *) vp << endl;
        return *this;
    }
};

/* If I make first arg const M2Stream &os, I get
\tests\t_stream_insertion_op\t_stream_insertion_op.cpp(39) : error C2666: 'M2Stream::operator <<' : 2 overloads have similar conversions
        \tests\t_stream_insertion_op\t_stream_insertion_op.cpp(13): could be 'M2Stream &M2Stream::operator <<(void *)'
        \tests\t_stream_insertion_op\t_stream_insertion_op.cpp(20): or 'const M2Stream &operator <<(const M2Stream &,const char *)'
        while trying to match the argument list '(M2Stream, const char [45])'
        note: qualification adjustment (const/volatile) may be causing the ambiguity
*/
const M2Stream & operator<<(M2Stream &os, const char *val)
{
    cout << "M2Stream good operator<<(const char *) called with " << val << endl;
    return os;
}


int main(int argc, char argv[])
{
    // This line calls void * overload, outputs: M2Stream bad operator<<(void *) called with literal char string on constructed temporary
    M2Stream() << "literal char string on constructed temporary";

    const char *s = "char string variable";

    // This line calls the const char * overload, and outputs: M2Stream good operator<<(const char *) called with char string variable
    M2Stream() << s;  

    // This line calls the const char * overload, and outputs: M2Stream good operator<<(const char *) called with literal char string on prebuilt object
    M2Stream m;
    m << "literal char string on prebuilt object";
    return 0;
}

Output:

M2Stream bad operator<<(void *) called with literal char string on constructed temporary
M2Stream good operator<<(const char *) called with char string variable
M2Stream good operator<<(const char *) called with literal char string on prebuilt object
+3
5

: Stream() << "hello"; operator<<, -. , , , char const*, .

, , . , , . - operator<< .

, , , char const*. - const. , . , operator<< MSV++. , .

M2Stream() << s; , ... , MSV++ , -const . 4, (- " ..." ).

, - < < void const*, a char const* , , , void const*.

, void*, void const*. , char*, char const[N] ( N - , ). . , void*. , MSV++. , , char const*. :

(2.13.4), , rvalue " char"; rvalue " wchar_t". . , , lvalue rvalue. [: . . D.]

+10

++:

  • , , rvalue.
  • r .
  • rvalue .

, ostream& operator<<(ostream&, const char*), , M2Stream, , , ( № 2); ostream& ostream::operator<<(void*) - . const char* .

, IOStreams operator<<() void* , operator<<() const char*, , , .

, . ? , ++, - , , ostream.

+5

, . , :

M2Stream ms;
ms << "the string";

, const.

, , const char *, , , ​​ VC. , , , "void *" "const char *". const char * ', , VC, const ref bind.

, 8.5.3/5 - , .

+1

, . :

M2Stream & operator<<( void *vp )

:

M2Stream & operator<<( const void *vp )

, , , const. , :

#include <iostream>
using namespace std;


class M2Stream
{
};

const M2Stream & operator<<( const M2Stream &os, const char *val)
{
    cout << "M2Stream good operator<<(const char *) called with " << val << endl;
    return os;
}


int main(int argc, char argv[])
{
    M2Stream() << "literal char string on constructed temporary";

    const char *s = "char string variable";

    // This line calls the const char * overload, and outputs: M2Stream good operator<<(const char *) called with char string variable
    M2Stream() << s;  

    // This line calls the const char * overload, and outputs: M2Stream good operator<<(const char *) called with literal char string on prebuilt object
    M2Stream m;
    m << "literal char string on prebuilt object";
    return 0;
}
0
source

You can use overload like this:

template <int N>
M2Stream & operator<<(M2Stream & m, char const (& param)[N])
{
     // output param
     return m;
}

As an added bonus, you now know that N is the length of the array.

0
source

Source: https://habr.com/ru/post/1707476/


All Articles