Error no match for operator operand types are std ostream

  • Forum
  • Beginners
  • no match for ‘operator<<‘ (operand types

no match for ‘operator<<‘ (operand types are ‘std::basic_ostream<char>’ and…

Hello:
Does anyone know how to fix the code? It´s a calculator that uses different classes.

Here is what the compiler says when I try to compile:
no match for ‘operator<<‘ (operand types are ‘std::basic_ostream<char>’ and ‘expression’)
cout << «= » << expression(ts) << endl;
^

Here is the main source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
#include <string>
#include "token_stream.h";
#include "expression.h";
#include "primary.h";
#include "term.h";
#include "myerror.h";
#include "token.h";


int main() try {
    Token tok{};
    Token_stream ts{};
    while( cin )
    {
    cout << "> "; // Prompt
    tok = ts.get();
    if( tok.kind == 'q' ) break;
    if( tok.kind == ';' ) continue;
    ts.putback( tok );
    cout << "= " << expression(ts) << endl; //I GET THE MISTAKE HERE
    }
    return 0;
}

catch( exception& e ) {

    cerr << e.what();
    return -2;
}

catch(const char* d ) {
    cerr << "Fehler:"<<endl<<d<<endl;
    return -1;
}

Here is the «expression.h» class:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef EXPRESSION_H
#define EXPRESSION_H
#include "token_stream.h"

class expression
{
public:
    expression(Token_stream& ts );
};

#endif // EXPRESSION_H

and here the expression.cpp part:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "expression.h"
#include "token_stream.h"
#include <iostream>;
#include "term.h"
#include "myerror.h"
#include "token.h"
#include "primary.h"
using namespace std;
#include <string>;
/*
expression::expression()
{
}
*/

double expression::expression( Token_stream& ts ) // "plus" and "minus"
{
    double d1{ term( ts ) };
    Token t1{};
    while( true )
    {
        t1 = ts.get();
        switch( t1.kind )
        {
        case '+': d1 += term( ts );
            break;
        case '-': d1 -= term( ts );
            break;
        default: ts.putback( t1 );
            return d1;
        }
    }
}

Hope you help me I don´t understand what I have done wrong :(

Last edited on

expression::expression is a constructor. Constructors are not allowed to return anything. The way you are using it, it seems that it shouldn’t be in a class. Just make it a function on its own and give it a meaningful name.

Alternatively, inititalize the class in a ctor and overload operator().

1
2
3
4
5
6
7
8
9
10
11
12
13
class expression {
    Token_stream &ts;
public:
    expression(Token_stream &ts) : ts(ts) {}
    double operator();
}

double expression::operator() {
    // your code here
}

expression e(ts);
cout << e() << 'n';

Which is better depends on how you are using it.

Last edited on

Here are the other classes:
My error class:

1
2
3
4
5
6
7
8
#ifndef MYERROR_H
#define MYERROR_H
#include <stdexcept>
#include <string>
using std::string;
void error( string s ) { throw std::runtime_error{ s }; }
void error( string s1, string s2 ) { error( s1 + s2 ); }
#endif // MYERROR_H 

primary.h:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef PRIMARY_H
#define PRIMARY_H
#include "token_stream.h"

class primary
{
public:
//    primary();
    primary( Token_stream& ts );
};

#endif // PRIMARY_H 

primary.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "primary.h"
#include "token_stream.h"
#include "expression.h"

/*primary::primary()
{
}
*/
primary::primary( Token_stream& ts ) // Numbers and parenthesis
{
    Token t3{ ts.get( ) };
    switch( t3.kind )
    {
    case '9': return t3.value;
    case '(': {
        double d3{ expression( ts ) };
        if( ts.get().kind != ')' ) error( "no right parenthesis" );
        return d3;
    }
    default: error( "no Primary" );
    }
}

term.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef TERM_H
#define TERM_H
#include "token_stream.h"
#include "primary.h"

class term
{
public:
//    term();
    term( Token_stream& ts );
};

#endif // TERM_H 

term.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "term.h"
#include "primary.h"
/*
term::term()
{

    }
*/
double term::term( Token_stream& ts ) // multiplication and division
    {
        double d2{ primary( ts ) };
        Token t2{};
        while( true )
        {
            t2 = ts.get();
            switch( t2.kind )
            {
            case '*': d2 *= primary( ts );
                break;
            case '/': {
                double divisor{ primary( ts ) };
                if( divisor == 0 ) error( "Division through 0" );
                d2 /= divisor;
                break;
            }
            default: ts.putback( t2 );
                return d2;
            }
        }
    }

token.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef TOKEN_H
#define TOKEN_H
#include <iostream>
using namespace std;
#include <string>


class Token {
public:
    char kind; // Categories of the symbols
    double value; // The value
    void print() const {
        if( kind == '9' ) cout << value;
        else cout << kind;
    }
    // Constructor, create a Token of a char:
    Token( const char& ch ) : kind{ch}, value{0.0} { /*doesn´t do anything */ }

    //Constructor, create a Number-Token of a double:
    Token( const double& val ) : kind{'9'}, value{val} { /* doesn´t do anything */ }

    // Standard constructor, create the standardtoken without specification:
    Token( ) : Token{0.0} { /* doesn´t do anything */ }
};

#endif // TOKEN_H 

token.cpp:

1
2
3
4
5
6
7
8
9
10
#include "token.h"


Token::Token( char ch ) : kind{ ch }, value{ 0.0 }
{}
Token::Token( double val ) : kind{ '9' }, value{ val }
{}
// Standard constructor
Token::Token( ) : Token{0.0}
{}

token_stream.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef TOKEN_STREAM_H
#define TOKEN_STREAM_H
#include "token.h";
#include "myerror.h";

class Token_stream
{
public:
    Token_stream();
    Token get( ); // Create Token of std::cin
    void putback( const Token& t )
    { // Trick: Buffer a Token
        if( full ) error( "void Token_stream::putback(), Buffer full" );
        buffer = t; full = true;
    }
private:
    bool full; // Is a token in Buffer?
    Token buffer; // Trick: Place to buffer a token
};

#endif // TOKEN_STREAM_H 

token_stream.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "token_stream.h"
#include <iostream>
#include "token.h"

using namespace std;

Token_stream::Token_stream()
{

}

Token Token_stream::get( )
{
if( full )
{
    full = false; return buffer;
}
char ch{ }; cin >> ch;
switch( ch ) {
    case ';': // Finalize a calculation
    case 'q': // End of Program
    case '(':
    case ')':
    case '+':
    case '-':
    case '*':
    case '/':
        return Token{ ch }; // every symbol has its own tokens
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9': // numbers as tokens
    {
        cin.putback( ch ); // the cin Stream has also a buffer
        double val{ }; cin >> val;
        return Token{ val };
    }
    default: error( "Token Token_stream::get(), unknown Token" );
}
}

Thank you for your help

Last edited on

Hi tpb:

you said I should try to give it a function of its own with a meaninful name. Here is the problem:
I have 3 functions:
1.- expression. 2.- term. 3.- primary.
All of these functions depend on each other.

We were told we should do the calculator with the given classes «token» and «token_stream», and that we should add the functions in the main part.

When I tried to add the functions, if I put at first the expression function, it needed the term function. When writing the term function, it needed «primary» and when writing primary, it needed «expression».

Someone said one should create classes for each function and then add them in the main part with include, therefore I did them.

Now you say I should do this functions on their own but to be honest, where? I was thinking about creating a class named «functions» and then putting all of them there, but I´m not sure if we are allowed to change the code of the functions or if that´s the only way that exists to make the program run.

Thanks!

So, instead of having the classes «expression», «term» and «primary» I added them in one class called «functions». Here is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include "token_stream.h"


class functions
{
public:
    functions();
    double expression(Token_stream& ts );
    double term( Token_stream& ts );
    double primary( Token_stream& ts );
};

#endif // FUNCTIONS_H

And here is the functions.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include "functions.h"

functions::functions()
{
}

double functions::expression(Token_stream &ts)
{
    double d1{ term( ts ) };
    Token t1{};
    while( true )
    {
        t1 = ts.get();
        switch( t1.kind )
        {
        case '+': d1 += term( ts );
            break;
        case '-': d1 -= term( ts );
            break;
        default: ts.putback( t1 );
            return d1;
        }
    }
}
double functions::term( Token_stream& ts )
{
    double d2{ primary( ts ) };
    Token t2{};
    while( true )
    {
        t2 = ts.get();
        switch( t2.kind )
        {
        case '*': d2 *= primary( ts );
            break;
        case '/': {
            double divisor{ primary( ts ) };
            if( divisor == 0 ) error( "Division durch 0" );
            d2 /= divisor;
            break;
        }
        default: ts.putback( t2 );
            return d2;
        }
    }
}
double functions::primary( Token_stream& ts )
{
    Token t3{ ts.get( ) };
    switch( t3.kind )
    {
    case '9': return t3.value;
    case '(': {
        double d3{ expression( ts ) };
        if( ts.get().kind != ')' ) error( "keine rechte Klammer" );
        return d3;
    }
    default: error( "kein Primary" );
    }
}

I changed the main part as well. I included the «functions.h» header and changed the line:

 
cout << "= " << functions.expression(ts) << endl;

Instead of

 
cout << "= " << expression(ts) << endl;

And now I receive this:
expected primary-expression before ‘.’ token
cout << «= » << functions.expression(ts) << endl;
^

You’re problem, as I understand it, is that you have three functions that create a circular dependency. That’s easy to deal with. Just put the function prototypes above the functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>

// function prototypes
int f(int n);
int g(int n);
int h(int n);

int main() { std::cout << f(1) << 'n'; }

int f(int n) { return n > 3 ? n : g(n); }   // f knows about g because of the prototype
int g(int n) { return h(n+1); }    // g knows about h because of the prototype
int h(int n) { return f(n+1); }    // h would know about f even without the prototype,
                                   // but it's still a good idea to have its prototype anyway 

Okay I understood I needed a class functions to use functions so I did it, thanks!

Okay I understood I needed a class functions to use functions so I did it,

Whatever. That’s the exact opposite of what I said. It is idiotic to create a Functions class.

This was my first topic and it is very disorganized so I will solve it and open another one.

Topic archived. No new replies allowed.

kosdin

13 / 12 / 3

Регистрация: 31.10.2019

Сообщений: 70

1

02.11.2020, 20:46. Показов 4093. Ответов 2

Метки нет (Все метки)


Занимаюсь изучением C++, столкнулся с такой проблемой:
Код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>
#include <vector>
using namespace std;
 
int main()
{
    vector<int> vec;
    int i;
    while (cin >> i)
        vec.push_back(i);
    cout << vec << endl;
}

При попытке вывести сам вектор, возникает вот такая ошибка «error: no match for ‘operator<<‘ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘std::vector<int>’)»

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Фрилансер

3703 / 2075 / 567

Регистрация: 31.05.2009

Сообщений: 6,683

02.11.2020, 20:48

2

А почему Вы решили, что вектор можно вывести таким образом? Выводите в цикле, поэлементно



1



Timurs

57 / 47 / 14

Регистрация: 23.02.2016

Сообщений: 429

02.11.2020, 20:51

3

kosdin, вектор по имени не выводится на печать также как и массив

C++
1
for (int elem : vec) cout << elem << " ";

Добавлено через 1 минуту
Black Fregat,

Не по теме:

если не ошибаюсь, то в питоне и джиэсе так выводится.



1



Overload resolution is one of C++ most complicated things and yet it works most of the time without the need to think about it.
In this mini-series, I will show you how to control this complex machinery so it is even more powerful and completely under your control.

The second post shows you a simple way to improve the error messages when overload resolution fails and how to customize it completely.

Motivation

The first example has probably the longest error message you’ll encounter:

#include <iostream>
#include <string>

struct foo
{
    // ...
};

std::ostream& operator>>(std::ostream &os, const foo &f)
{
    // print f
    return os;
}

int main()
{
    foo f;
    std::cout << f;
}

The programmer has defined a user-defined type with something he thought was an output operator (or stream insertion operator, if you prefer).
But instead of overloading operator<<, he made a typo and overloaded operator>>.

This happens to me all the time, I have to admit.

GCC generates an error message starting with:

main.cpp: In function ‘int main()’:
 main.cpp:18:15: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘foo’)
    std::cout << f;
               ^
 In file included from /usr/include/c++/5.2.0/iostream:39:0,
                 from main.cpp:1:
 /usr/include/c++/5.2.0/ostream:628:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = foo] <near match>
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^
 /usr/include/c++/5.2.0/ostream:628:5: note:   conversion of argument 1 would be ill-formed:
 main.cpp:18:18: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
     std::cout << f;
                  ^
 In file included from /usr/include/c++/5.2.0/iostream:39:0,
                 from main.cpp:1:
> /usr/include/c++/5.2.0/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
       operator<<(__ostream_type& (*__pf)(__ostream_type&))
       ^
 ....

The error message is followed by a list of all other candidates, 216 lines with a total of 17,686 characters!
All because of a simple typo.

Another example

Let’s consider a simpler, shorter example I can extend without much difficulties.

You probably know — and hopefully not use! — the old C trick — or hack — to calculate the size of an array:
sizeof(array) / sizeof(array[0]).
It has a problem, though: array’s decay to pointers at almost every instance and even if you declare a function parameter as array, it is actually a pointer!
This behavior was inherited from C.

C’s great.

So, if a naive programmer uses the array trick inside a function like so, he has a problem:

void func(int array[]) // actually a pointer, not an array!
{
    auto size = sizeof(array) / sizeof(array[0]); // actually: sizeof(int*) / sizeof(int)!
    ....
}

int main()
{
    int array[4];
    func(array); // array to pointer decay here
}

The code does not calculate the size of an array, it divides the size of a pointer by the size of an int.
Unless on very strange systems, this is probably not 4.

So, what would a C++ programmer do?

He would use std::array. Or pass a range to the function.

But let’s ignore the (far better) alternatives.

A C++ programmer would write a function, let’s name it array_size, that calculates the size.
C++ has templates, so there is no need to use the old sizeof “trick”:

template <typename T, std::size_t N>
constexpr std::size_t array_size(T(&)[N])
{
    return N:
}

If you have never seen T(&)[N], this is an (unnamed) reference to an array of N Ts.
Yes, you can have references to array.
With a name it would be T(&array)[N], but it is not needed here.

The syntax is great, isn’t it?

This function takes an array by reference and let template argument deduction figure out how big the array is.

Now, if the programmer would use array_size() instead of sizeof, he will get an error:

prog.cpp: In function 'void func(int*)':
prog.cpp:17:18: error: no matching function for call to 'array_size(int*&)'
  auto size = array_size(array);
                              ^
prog.cpp:4:23: note: candidate: template<class T, unsigned int N> constexpr std::size_t array_size(T (&)[N])
 constexpr std::size_t array_size(T(&)[N])
                       ^
prog.cpp:4:23: note:   template argument deduction/substitution failed:
prog.cpp:17:18: note:   mismatched types 'T [N]' and 'int*'
  auto size = array_size(array);
                              ^

We have transformed a runtime bug into a compile-time error.
This is by far better, but the whole point of this post is to improve the error messages, so let’s do it.

Deleted fallback

In the previous post I have shown you how you can use = delete on arbitrary functions.
If the function is overloaded, this will prevent calling it with the argument types in the deleted candidate.

This is exactly what we want!

If you pass anything but an array to array_size(),
this shouldn’t list the base candidate.
So we need a fallback function that is always valid.
But this fallback should not exist, so we delete it.

For the small example with only one valid candidate, this doesn’t seem to be that useful.
But bear with me for the rest of this paragraph.

But what is the argument of the fallback function?
It must be able to take anything and must never be a better match than the valid function,
otherwise the right types will go for the fallback.

If you are thinking “forwarding reference”, this is a bad idea.
T&& is very easily a better match than anything else and will be prefered.
Scott Meyers spents the whole item 26 on this topic in his book “Effective Modern C++”.

In this case, simply writing a template function taking a single argument by value is sufficient.
An array type will always bind to the first overload, since it is more specialized,
everything else to the by-value overload.
So we declare this fallback overload and mark it as delete:

template <typename T, std::size_t N>
constexpr std::size_t array_size(T(&)[N])
{
    return N:
}

// deleted fallback overload
template <typename T>
constexpr std::size_t array_size(T) = delete;

The same call now results in:

 prog.cpp: In function 'void func(int*)':
 prog.cpp:20:30: error: use of deleted function 'constexpr std::size_t array_size(T) [with T = int*; std::size_t = unsigned int]'
  auto size = array_size(array);
                              ^
 prog.cpp:10:23: note: declared here
 constexpr std::size_t array_size(T) = delete;
                       ^

This may not seem as a big improvement to the previous array,
but for a function with many valid overloads (like operator>>), this can be big,
since the compiler will not list all the other candidates.

I could end the post right here, but I am not quite happy.
The error message does not really give a reason why the overload resolution failed.
Wouldn’t it be nice to give a complete customized error message instead?

Customized error message

What I’d like to have is a custom error message when the fallback is chosen.
Custom error message sounds a lot like static_assert, so let’s try it:

template <typename T>
constexpr std::size_t array_size(T)
{
    static_assert(false, "array-to-pointer decay has occured, cannot give you the size");
    return 0; // to silence warnings
}

I’ve inserted a static_assert(false, ...) inside the function.
This should trigger an error message when it is chosen by overload resolution.

Except that the static_assert is eager to mark the code as ill-formed; §14.6[temp.res]/8:

[…] If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required. […]

This bascially means, “as soon as you see that a template has invalid code, you may say so immediately”.
And clang and GCC do it prior to instantiation and let the static_assert trigger immediately,
while MSVC waits until instantiation.

So we need to force the compiler to evaluate the static_assert only when the template is actually instantiated.
This can be done by making the boolean expression dependent on the template parameter.
Then the compiler cannot evaluate the expression prior instantiation.
The most common way to do is the following:

template <typename T>
constexpr std::size_t array_size(T)
{
    static_assert(sizeof(T) != sizeof(T), "array-to-pointer decay has occured, cannot give you the size");
    return 0; // to silence warnings
}

The size of T depends on the actual instantiated T, so it is only available after instantiation.
This works, but I don’t find the solution very readable and a smart compiler could figure out that sizeof(T) is always equal to sizeof(T)
and thus trigger the static_assert prior instantation.

So I suggest the following:

template <typename T>
struct not_an_array
{
    static constexpr bool error = false;
};

template <typename T>
constexpr std::size_t array_size(T)
{
    static_assert(not_an_array<T>::error, "array-to-pointer decay has occured, cannot give you the size");
    return 0; // to silence warnings
}

This works because not_an_array could have been specialized for certain types with a different value of the error constant.
Using this fallback in the original code yields the following error message:

 prog.cpp: In instantiation of 'constexpr std::size_t array_size(T) [with T = int*; std::size_t = unsigned int]':
 prog.cpp:24:30:   required from here
 prog.cpp:18:5: error: static assertion failed: array-to-pointer decay has occured, cannot give you the size
     static_assert(not_an_array<T>::error, "array-to-pointer decay has occured, cannot give you the size");
     ^

This is a completely customized error message, which is what I wanted.

Note that this technique has a drawback:
You then can’t use SFINAE to detect whether or not the call is well-formed,
as the static_assert() doesn’t look into the function body.

SFINAE still works with = delete, it’s a shame you can’t give it a custom message.
There is a proposal but it hasn’t been accepted as of yet.

Conclusion

If you call a function and overload resolution fails, the error messages are often very long listing all possible candidates.
To avoid this, simply create a templated fallback overload that is selected as last resort.
This fallback overload is either deleted or consists of a static_assert with a false boolean depending on the template parameter.
The latter version allows for a completely customized error message.

It can be applied if you have a lot of overloads of a function and want a clear message when there is no possible candidate (like operator<<)
or even when you have only a single function but want more information inside the error message, when it fails (like the array_size above).

In the next post of the series, I will show you a very powerful method to control exactly how to select an overload: tag dispatching.

If you’ve liked this blog post, consider donating or otherwise supporting me.

This blog post was written for my old blog design and ported over. If there are any issues, please let me know.

Понравилась статья? Поделить с друзьями:
  • Error no logon servers nltest
  • Error no launcher gta 5 что делать windows 10
  • Error no launcher gta 5 скачать
  • Error no ums support in radeon module
  • Error no input files codeblocks