Ошибка компилятора c2678

description title ms.date f1_keywords helpviewer_keywords ms.assetid

Learn more about: Compiler Error C2678

Compiler Error C2678

11/04/2016

C2678

C2678

1f0a4e26-b429-44f5-9f94-cb66441220c8

Compiler Error C2678

binary ‘operator’ : no operator defined which takes a left-hand operand of type ‘type’ (or there is no acceptable conversion)

To use the operator, you must overload it for the specified type or define a conversion to a type for which the operator is defined.

C2678 can occur when the left-hand operand is const-qualified but the operator is defined to take a non-const argument.

Examples

The following sample generates C2678 and shows how to fix it:

// C2678a.cpp
// Compile by using: cl /EHsc /W4 C2678a.cpp
struct Combo {
   int number;
   char letter;
};

inline Combo& operator+=(Combo& lhs, int rhs) {
   lhs.number += rhs;
   return lhs;
}

int main() {
   Combo const combo1{ 42, 'X' };
   Combo combo2{ 13, 'Z' };

   combo1 += 6; // C2678
   combo2 += 9; // OK - operator+= matches non-const Combo
}

C2678 can also occur if you do not pin a native member before calling a member function on it.

The following sample generates C2678 and shows how to fix it.

// C2678.cpp
// compile with: /clr /c
struct S { int _a; };

ref class C {
public:
   void M( S param ) {
      test = param;   // C2678

      // OK
      pin_ptr<S> ptest = &test;
      *ptest = param;
   }
   S test;
};

I am really confused on why I am getting following compilation error.
Microsoft Visual Studio Compiler.

error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::string' (or there is no acceptable conversion)

#include <stdio.h>
#include <iostream>
#include <sstream>
#include <iterator>

class MyException {
public:
    MyException(    std::string message, 
                        int line = 0) : m_message(message),
                                        m_line(line) {}
    const char* what() const throw(){
        if ( m_line != 0 ) {
            std::ostringstream custom_message;
            custom_message << "Parsing Error occured at ";
            custom_message << m_line << " Line : ";
            custom_message << m_message;        
            m_message = custom_message.str();
        }
        return m_message.c_str();
    }
private:
    std::string m_message;
    int m_line;
};
int main(int argc, char **argv) {
    try {
        // do something
    }catch(MyException &e){
        std::cout << e.what();
    }
}

Error is coming at line
m_message = custom_message.str();

asked Aug 11, 2011 at 6:20

Avinash's user avatar

1

You declare the method as const

const char* what() const throw(){

but then you try to change the object

m_message = custom_message.str();

so you get an error.

What you should do instead is construct the custom message in the constructor.

class MyException {
public:
    MyException(const std::string& message, int line = 0) : 
        m_message(message), m_line(line) {
        if ( m_line != 0 ) {
            std::ostringstream custom_message;
            custom_message << "Parsing Error occured at ";
            custom_message << m_line << " Line : ";
            custom_message << m_message;        
            m_message = custom_message.str();
        }
    }
    const char* what() const throw(){
        return m_message.c_str();
    }
private:
    std::string m_message;
    int m_line;
};

Also I changed your code to pass the std::string by reference, which is usual practice.

answered Aug 11, 2011 at 6:24

john's user avatar

johnjohn

84k4 gold badges56 silver badges80 bronze badges

You are trying to assign to MyException::m_message inside a const-qualified method MyException::what(). Inside such what() the entire *this object is considered to be const, which means that m_message member is also const. You can’t assign anything to a const-qualified std::string object, since std::string‘s assignment operator requires a modifiable (i.e. a non-const one) object on the left-hand side. You are supplying a const one.

If you really want to be able to modify the m_message inside what(), you should declare it as mutable member of the class (in this case it appears to be a good idea). Or use some other approach.

As @john noted, in your specific case it makes more sense to actually build m_message in constructor instead of postponing it till what(). I don’t really understand why you’d even want to rebuild your m_message every time you call what(). Unless your m_line is expected to change somehow from one call to what() to another, there’s really no need to do it every time.

answered Aug 11, 2011 at 6:24

AnT stands with Russia's user avatar

In addition to the other answers;

You’re not including the <string> header, which may be the cause of a problem later.

Something that used to get me a lot is that some std:: headers include others, which allows you to use a class, but maybe only with limited functionality because the std:: headers that they include are the bare minimum that is needed for that file to run. This is quite an annoyance because sometimes you declare a std:: class such as string and you haven’t included the header, the definition will be fine but everything else may or may not work — leading you to a lot of debugging because the definition worked fine.

answered Aug 11, 2011 at 6:28

Seb Holzapfel's user avatar

Seb HolzapfelSeb Holzapfel

3,7831 gold badge19 silver badges22 bronze badges

See the declaration of the what() function, it is marked const (the second const on the line). That means that it cannot alter any member variables, in your case the m_message string. That is why you get the error.

Now, how do you fix it?

Your code is wrong, your what() function will prepend the "Parsing Error occured at " etc. text each time you invoke the what() function. So, instead of doing that having to modify the m_message member, I suggest that you format the entire message in the ctor of the class:

MyException(std::string message, int line = 0)
{
    if (line != 0)
    {
        std::ostringstream custom_message;
        custom_message << "Parsing Error occured at ";
        custom_message << line << " Line : ";
        custom_message << message;        
        m_message = custom_message.str();            
    }
    else
        m_message = message;
}

answered Aug 11, 2011 at 6:36

wilx's user avatar

wilxwilx

17.6k6 gold badges59 silver badges113 bronze badges

При компиляции Visual Studio выдает ошибку:
error C2678: бинарный «<«: не найден оператор, принимающий левый операнд типа «const _Ty» (или приемлемое преобразование отсутствует).
Что это значит и как ее исправить?
P.S. Если данные пояснения помогут, то вот они:
Структура Shape — прямоугольник, первые две координаты у которого (x0, y0) — левая нижняя его вершина, вторые две
(x1, y1) — правая верхняя. Вершины прямоугольника лежат в узлах целочисленной решетки.
Структура Point — точка хранит координаты точки x0, y0.
Функция PointInShape проверяет, лежит ли точка в прямоугольнике.
Функция PointInArea проверяет, лежит ли точка в каком-нибудь из прямоугольников, а также посещали ли мы ее ранее.
Вектор shapes — набор прямоугольников
Словарь used хранит информацию, посещена ли вершина point.
Словарь dist хранит расстояния до вершин от стартовой.
Во входном файле задано количество прямоугольников n и в следующих n строках заданы прямоугольники в виде
координат левой нижней и правой верхней вершин.
В последних двух строках заданы координаты стартовой и конечной вершин.
Разрешено посещать только те вершины, которые находятся хотя бы в одном из многоугольников.
Ходить можно только конем, как в шахматах (на две клетки вверх/вниз и на одну в перпендикулярном направлении).
Необходимо вывести в выходной файл расстояние length между вершинами или -1, если между ними нет пути.
Пример входных данных:
3
0 0 2 2
1 2 4 2
4 1 6 3
0 0
1 1
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <iostream>
#include <cstdlib>
#include <vector>
#include <map>
#include <fstream>
#include <queue>
using namespace std;


struct Shape {
	long x0, y0, x1, y1;
	explicit Shape(const long X0, const long Y0, const long X1, const long Y1) {
		x0 = X0;
		y0 = Y0;
		x1 = X1;
		y1 = Y1;
	}
};

struct Point {
	long x0, y0;
	explicit Point(const long X0,const long Y0) {
		x0 = X0;
		y0 = Y0;
	}
};

bool PointInShape(const Shape& shape,const Point& point) {
	if (point.x0 >= shape.x0 && point.x0 <= shape.x1 &&
		point.y0 >= shape.y0 && point.y0 <= shape.y1) return true;
	return false;
}

bool PointInArea(const vector <Shape>& sh, const map <Point, bool>& u,const Point& point) {
	bool InUsed = u.count(point);
	for (const Shape& s : sh) {
		if (PointInShape(s, point) && !InUsed) return true;
	}
	return false;
}

int main() {
	ifstream file_in("infile.txt");
	ofstream file_out("outfile.txt");
	long n;
	file_in >> n;
	long x1, y1, x2, y2;
	vector <Shape> shapes;
	map <Point, bool> used;
	map <Point, long> dist;
	for (int i = 0; i < n; ++i) {
		file_in >> x1 >> y1 >> x2 >> y2;
		shapes.push_back(Shape( x1, y1, x2, y2 ));
	}
	file_in >> x1 >> y1 >> x2 >> y2;
	const Point start(x1, y1);
	const Point end(x2, y2);
	queue <Point> points;
	points.push(start);
	dist[start] = 0;
	long length = -1;
	while (!points.empty()) {
		Point point = points.front();
		points.pop();
		for (const Point& p : {Point(point.x0+2, point.y0+1),
			Point(point.x0+2, point.y0-1),
			Point(point.x0+1, point.y0+2),
			Point(point.x0-1, point.y0-2)}) {
			if (p.x0 == end.x0 && p.y0 == end.y0) {
				length = dist[point] + 1;
				file_out << length;
				return 0;
			}
			else {
				if (PointInArea(shapes, used, p)) {
					points.push(p);
					dist[p] = dist[point] + 1;
				}
			}
		}
	}
	file_out << length;
	return 0;
}

The full error is: error C2678: binary ‘<‘ : no operator found which takes a left-hand operand of type ‘const sf::Vector2f’ (or there is no acceptable conversion)
What upsets me is that the error gives no location, so this could literally be anywhere in my program. Here is the function that I think does it, but I have plenty more to post if this isn’t it.

1
2
3
4
5
6
7
8
9
10
if(sf::Mouse::isButtonPressed(sf::Mouse::Left)){
			sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
			//int xc = localMousePos.x;
			//int yc = localMousePos.y;
			for(int i = 0; i < board.GetBoxes().size(); i++){
				sf::FloatRect fr = board.GetRect()[i].getGlobalBounds();
				if(fr.contains(mouse)){
					std::cout << board.GetBoxes()[i].GetName();
				}
			}

GetBoxes() and GetRect() return vectors of my Box class objects and sf::RectangleShape objects. What does this error even mean, and how do I get around it?

No way. Even the worst template errors give a line number. Post the contents of the output window.

The error is not in that code. The only < operator is in your for statement, and it is not using sf::Vector2f.

helios is right. The error message always has the line number in it (if it’s a compiler error). You just must not be seeing it.

Sorry, I meant no line number in my own code.

error C2678: binary ‘<‘ : no operator found which takes a left-hand operand of type ‘const sf::Vector2f’ (or there is no acceptable conversion) c:program files (x86)microsoft visual studio 11.0vcincludexstddef 180 1 TicTacToe

Looking in the xstddef file, I have no way of determining what actually went wrong

@Disch: ok, so how about this code? I am also working with a std map that holds an sf::Vector2f

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Board::FillVectors(){
	for(int i = 0; i < 9; i++){
		sf::RectangleShape rectangle(sf::Vector2f(80, 80));
		Box box;

		rectangles.push_back(rectangle);
		boxes.push_back(box);
	}
	for(int i = 1; i < boxes.size() + 1; i++){
		std::cout << boxes[i].GetName();
		rectangles[i].setPosition((i * 20) + 10, (i * 20) + 10);
	}
}

Box &Board::FillMap(){
	for(std::map<sf::Vector2f, std::vector<Box>>::const_iterator it = boxMap.begin(); it != boxMap.end(); ++it){
		for(int i = 0; i < boxes.size(); i++){
			boxMap[rectangles[i].getOrigin()];
		}
	}
}

That’s in Boad.cpp. Here’s board.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Board{
public:
	Board(ImageManager &im);
	~Board();

	void FillVectors();
	Box &FillMap();

	std::vector<Box> &GetBoxes();
	std::vector<sf::RectangleShape> &GetRect();

	sf::Sprite GetGameBoard();
private:
	sf::Sprite gameBoard;

	ImageManager &imgr;

	std::vector<sf::RectangleShape> rectangles;
	std::vector<Box> boxes;

	std::map<sf::Vector2f, std::vector<Box>> boxMap;
};

Last edited on

Template errors output a sort of stack of errors and you have to figure out where your code is. That’s why I asked you to post the contents of the window. Post everything.

This:

std::map<sf::Vector2f, std::vector<Box>> boxMap;

std::map uses the < operator to order its keys. There is no < operator defined for sf::Vector2f.

You have a few options… the least drastic of which would be to provide your own compare functor for the map:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<typename T>
struct VectorCompare
{
    bool operator() (const sf::Vector2<T>& a, const sf::Vector2<T>& b)
    {
        if(a.y < b.y)  return true;
        if(a.y > b.y)  return false;
        return (a.x < b.x);
    }
};

// ...

// then you can do this:
std::map<sf::Vector2f, std::vector<Box>, VectorCompare<float>> boxMap;

Last edited on

@helios: ok, here are all the warnings that come up with the one error:

Warning 1 warning C4018: ‘<‘ : signed/unsigned mismatch c:usersjordandocumentsvisual studio 2012 projectstictactoetictactoeboard.cpp 23 1 TicTacToe
Warning 2 warning C4244: ‘argument’ : conversion from ‘int’ to ‘float’, possible loss of data c:usersjordandocumentsvisual studio 2012projectstictactoetictactoeboard.cpp 25 1 TicTacToe
Warning 3 warning C4018: ‘<‘ : signed/unsigned mismatch c:usersjordandocumentsvisual studio 2012projectstictactoetictactoeboard.cpp 31 1 TicTacToe
Error 4 error C2678: binary ‘<‘ : no operator found which takes a left-hand operand of type ‘const sf::Vector2f’ (or there is no acceptable conversion) c:program files (x86)microsoft visual studio 11.0vcincludexstddef 180 1 TicTacToe

The locations the warnings refer to (Board.cpp) can be found in the code I posted earlier.

@Disch ok thanks, but what would a third element in my map do to how it functions?

Last edited on

wh1t3crayon: you still are not posting the full error message.

When I put similar code in VS (which it looks like you are using), I get the below error:


1>  main.cpp
1>c:program files (x86)microsoft visual studio 11.0vcincludexstddef(180): error C2678: binary '<' : no operator found which takes a left-hand operand of type 'const sf::Vector2f' (or there is no acceptable conversion)
1>          c:usersbenc++ libssfml-2.0includesfmlsystemtime.hpp(185): could be 'bool sf::operator <(sf::Time,sf::Time)' [found using argument-dependent lookup]
1>          c:usersbenc++ libssfml-2.0includesfmlsystemstring.hpp(398): or       'bool sf::operator <(const sf::String &,const sf::String &)' [found using argument-dependent lookup]
1>          c:usersbenc++ libssfml-2.0includesfmlwindowvideomode.hpp(141): or       'bool sf::operator <(const sf::VideoMode &,const sf::VideoMode &)' [found using argument-dependent lookup]
1>          c:usersbenc++ libssfml-2.0includesfmlnetworkipaddress.hpp(227): or       'bool sf::operator <(const sf::IpAddress &,const sf::IpAddress &)' [found using argument-dependent lookup]
1>          while trying to match the argument list '(const sf::Vector2f, const sf::Vector2f)'
1>          c:program files (x86)microsoft visual studio 11.0vcincludexstddef(179) : while compiling class template member function 'bool std::less<_Ty>::operator ()(const _Ty &,const _Ty &) const'
1>          with
1>          [
1>              _Ty=sf::Vector2f
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludemap(194) : see reference to function template instantiation 'bool std::less<_Ty>::operator ()(const _Ty &,const _Ty &) const' being compiled
1>          with
1>          [
1>              _Ty=sf::Vector2f
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludetype_traits(743) : see reference to class template instantiation 'std::less<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=sf::Vector2f
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludextree(1028) : see reference to class template instantiation 'std::is_empty<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::less<sf::Vector2f>
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludemap(67) : see reference to class template instantiation 'std::_Tree<_Traits>' being compiled
1>          with
1>          [
1>              _Traits=std::_Tmap_traits<sf::Vector2f,std::vector<Box>,std::less<sf::Vector2f>,std::allocator<std::pair<const sf::Vector2f,std::vector<Box>>>,false>
1>          ]
1>          c:usersbendocumentsvisual studio 2012projectswxtimetestmain.cpp(28) : see reference to class template instantiation 'std::map<_Kty,_Ty>' being compiled
1>          with
1>          [
1>              _Kty=sf::Vector2f,
1>              _Ty=std::vector<Box>
1>          ]

The bolded/underlined section tells you where in my code the error was.

@Disch ok thanks, but what would a third element in my map do to how it functions?

There is not 3rd element. The map behaves exactly the same… it has one value per key. The only thing I changed is how it compares its keys.

std::map needs to be able to compare keys so that it can order them, and look up elements. By default, it uses the < operator to compare keys. However, as mentioned, sf::Vector2f has no operator, so we have to give it something else.

I gave it a VectorCompare struct so it will now use that struct to compare two sf::Vector2fs.

ah, you meant the build code. My apologies. So here is the full output:

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
1
1>  Board.cpp
1>c:usersjordandocumentsvisual studio 2012projectstictactoetictactoeboard.cpp(23): warning C4018: '<' : signed/unsigned mismatch
1>c:usersjordandocumentsvisual studio 2012projectstictactoetictactoeboard.cpp(31): warning C4018: '<' : signed/unsigned mismatch
1>c:program files (x86)microsoft visual studio 11.0vcincludexstddef(180): error C2678: binary '<' : no operator found which takes a left-hand operand of type 'const sf::Vector2f' (or there is no acceptable conversion)
1>          c:program files (x86)sfml-2.1includesfmlsystemtime.hpp(185): could be 'bool sf::operator <(sf::Time,sf::Time)' [found using argument-dependent lookup]
1>          c:program files (x86)sfml-2.1includesfmlsystemstring.hpp(398): or       'bool sf::operator <(const sf::String &,const sf::String &)' [found using argument-dependent lookup]
1>          c:program files (x86)sfml-2.1includesfmlwindowvideomode.hpp(141): or       'bool sf::operator <(const sf::VideoMode &,const sf::VideoMode &)' [found using argument-dependent lookup]
1>          while trying to match the argument list '(const sf::Vector2f, const sf::Vector2f)'
1>          c:program files (x86)microsoft visual studio 11.0vcincludexstddef(179) : while compiling class template member function 'bool std::less<_Ty>::operator ()(const _Ty &,const _Ty &) const'
1>          with
1>          [
1>              _Ty=sf::Vector2f
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludemap(194) : see reference to function template instantiation 'bool std::less<_Ty>::operator ()(const _Ty &,const _Ty &) const' being compiled
1>          with
1>          [
1>              _Ty=sf::Vector2f
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludetype_traits(743) : see reference to class template instantiation 'std::less<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=sf::Vector2f
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludextree(1028) : see reference to class template instantiation 'std::is_empty<_Ty>' being compiled
1>          with
1>          [
1>              _Ty=std::less<sf::Vector2f>
1>          ]
1>          c:program files (x86)microsoft visual studio 11.0vcincludemap(67) : see reference to class template instantiation 'std::_Tree<_Traits>' being compiled
1>          with
1>          [
1>              _Traits=std::_Tmap_traits<sf::Vector2f,std::vector<Box>,std::less<sf::Vector2f>,std::allocator<std::pair<const sf::Vector2f,std::vector<Box>>>,false>
1>          ]
1>          c:usersjordandocumentsvisual studio 2012projectstictactoetictactoeboard.h(29) : see reference to class template instantiation 'std::map<_Kty,_Ty>' being compiled
1>          with
1>          [
1>              _Kty=sf::Vector2f,
1>              _Ty=std::vector<Box>
1>          ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Yeah, so…. you look at the bottom of that stack… and it tells you the line that the problem is on:

 
c:usersjordandocumentsvisual studio 2012projectstictactoetictactoeboard.h(29)

Line 29 of board.h.

Which is the line I pointed to before:

std::map<sf::Vector2f, std::vector<Box>> boxMap;

How do I use your version of the map? I have this so far, but I’m getting illegal indirection errors for it.

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
#pragma once
#include "stdafx.h"
#include <vector>
#include <map>
#include "Box.h"
#include "SFML/Graphics.hpp"
#include "ImageManager.h"

template<typename T>
struct VectorCompare
{
    bool operator() (const sf::Vector2<T>& a, const sf::Vector2<T>& b){
        if(a.y < b.y) return true;
        if(a.y > b.y) return false;
        return (a.x < b.x);
    }
};


class Board{
public:
	Board(ImageManager &im);
	~Board();

	void FillVectors();
	Box &FillMap();

	std::vector<Box> &GetBoxes();
	std::vector<sf::RectangleShape> &GetRect();

	sf::Sprite GetGameBoard();
private:
	sf::Sprite gameBoard;

	ImageManager &imgr;

	std::vector<sf::RectangleShape> rectangles;
	std::vector<Box> boxes;

	std::map<sf::Vector2f, std::vector<Box>, VectorCompare<float>> boxMap;
};

and then in my function

1
2
3
4
5
6
7
Box &Board::FillMap(){
	for(std::map<sf::Vector2f, std::vector<Box>, VectorCompare<float>>::const_iterator it = boxMap.begin(); it != boxMap.end(); ++it){
		for(int i = 0; i < boxes.size(); i++){
			boxMap[rectangles[i].getOrigin()];
		}
	}
}

Error 4 error C2664: ‘std::_Tree_iterator<_Mytree> std::_Tree<_Traits>::insert(std::_Tree_const_iterator<_Mytree>,std::pair<_Ty1,_Ty2> &&)’ : cannot convert parameter 2 from ‘int’ to ‘std::pair<_Ty1,_Ty2> &&’ c:program files (x86)microsoft visual studio 11.0vcincludextree 1319 1 TicTacToe
Error 3 error C2100: illegal indirection c:program files (x86)microsoft visual studio 11.0vcincludextree 1319 1 TicTacToe

I’m pretty close to scrapping the map idea and finding some other way to link an area of coordinates to a class object. Are there easier ways to do this?

How do I use your version of the map?

Exactly the same as you would use your own version of the map. The only thing that really changes is the declaration line.

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
#include <sfml.h>
#include <map>
#include <iostream>
#include <vector>

template<typename T>
struct VectorCompare
{
    bool operator() (const sf::Vector2<T>& a, const sf::Vector2<T>& b)
    {
        if(a.y < b.y)  return true;
        if(a.y > b.y)  return false;
        return (a.x < b.x);
    }
};

int main()
{
    // make a map:
    std::map<sf::Vector2f, int, VectorCompare<float>>  example;

    // put some crap in it
    example[sf::Vector2f(10,4)] = 6;
    example[sf::Vector2f(10,8)] = 9;

    // iterate over it:
    for(auto& i : example)
    {
        std::cout << "key.x=" << i.first.x << " key.y="
              << i.first.y << " value=" << i.second << std::endl;
    }
}
key.x=10 key.y=4 value=6
key.x=10 key.y=8 value=9

and then in my function [snip]
for(std::map<sf::Vector2f, std::vector<Box>, VectorCompare<float>>::const_iterator it = boxMap.begin(); it != boxMap.end(); ++it){

Good god, man. Use auto or at least typedef that madness:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//////////////////////
// option 1, auto + ranged-based for loop:
for(auto& it : boxMap)

//////////////////////
// option 2: auto, regular for loop:
for(auto it = boxMap.begin(); it != boxMap.end(); ++it)

//////////////////////
// option 3:  typedef

// when defining your map
typedef std::map<sf::Vector2f,std::vector<Box>,VectorCompare<float>> BoxMap_t;
BoxMap_t boxMap;

// then for your for loop:
for(boxMap_t::const_iterator it = boxMap.begin(); it != boxMap.end(); ++it)

I’m pretty close to scrapping the map idea and finding some other way to link an area of coordinates to a class object.

That might not be a bad idea. Using a Vector2f as a key seems extremely strange to me.

Can you elaborate on what you’re trying to do? Like at a high level, conceptual level?

Last edited on

Good god, man. Use auto or at least typedef that madness:

Thanks, you’re the first person to show me another way of even doing a for loop.

Can you elaborate on what you’re trying to do? Like at a high level, conceptual level?

Conceptually, I have a game board, class Board, that takes up the whole window. This board will be divided into 9 equal areas, defined by the class Box. E.g. a tic tac toe board. The Board holds a vector of 9 Box objects.

Conceptually, here is where I am stuck: I want to give each of these box objects an area of coordinates on the screen that defines them, and access them when clicked (i.e. if I click on the top left corner, then «box1» from the vector of Boxes is accessed, and I can do stuff such as draw its sprite.) I tried mapping some sfml rectangles to the box objects since sfml rectangles are graphical and can actually be placed invisibly on the screen. I just don’t know how to link the box objects to the sfml rectangle objects.

A simple grid can be accomplished with a 2D array. Although I hate using 2D arrays directly since their syntax is awkward… I usually abstract them behind another class.

Here’s something I whipped up recently that you can use:

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

template<typename T>
class Grid
{      
public:
    Grid() : wd(0), ht(0) {}
    Grid(int width, int height, const T& t = T())
        : wd(std::max(0,width))
        , ht(std::max(0,height))
        , data(wd*ht,t)
    {}
  
    T& get(int x, int y)                    { return data[(y*wd)+x]; }
    const T& get(int x, int y) const        { return data[(y*wd)+x]; }
    
    T& operator (int x, int y)              { return get(x,y);       }
    const T& operator (int x, int y) const  { return get(x,y);       }
    
    int width() const                       { return wd;            }
    int height() const                      { return ht;            }

    void resize(int w, int h)
    {
        if(w < 0)       w = 0;
        if(h < 0)       h = 0;
        std::vector<T>      d(w*h);
        
        int mw = std::min(w,wd);
        int mh = std::min(h,ht);
        for(int y = 0; y < mh; ++y)
        {
            for(int x = 0; x < mw; ++x)
            {
                d[ (y*w)+x ] = std::move( data[ (y*wd)+x ] );
            }
        }

        data.swap(d);
        wd = w;
        ht = h;
    }
    
private:
    int                 wd;
    int                 ht;
    std::vector<T>      data;
};

Usage example:

1
2
3
4
5
6
7
Grid<std::vector<Box>> grid(3,3);  // <- make a 3x3 grid

// add something to the upper left corner
grid(0,0).push_back( Box() );

// add something else to the center
grid(1,1).push_back( Box() );

I want to give each of these box objects an area of coordinates on the screen that defines them, and access them when clicked

Converting pixel coordinates to ‘grid’ coordinates is a simple division. Just divide by the number of pixels per grid entry.

Example:

1
2
3
4
5
6
7
8
sf::Vector2i mouse = whereverTheUserClicked();

const int pixelsPerGridEntry = 200;  // assuming each "area" is a 200x200 pixel square

auto gridPos = mouse / pixelsPerGridEntry;  // get the position in the grid

grid(gridPos.x, gridPos.y)  // <- this is the vector<Box> that the user clicked on.  Do
     //  whatever with it. 

Thank you for the replies. Your last post finally made me understand how templates work, but I too was hoping to avoid 2d arrays. I eventually got the code to work after thinking inside the Box (pun intended), and I just gave each box object their own sf::RectangleShape inside the box class. That way, the boxes are already linked to a set of coordinates upon creation. So for anybody else who is having a similar problem:

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
class Box{
public:
	Box();
	~Box();

	void SetRect();
	sf::RectangleShape &GetRect();

	void SetDrawn(bool drawn);
	bool GetDrawn();

	void SetShape(char shape);
	sf::Sprite GetShape();

	std::string GetName();
private:
	sf::RectangleShape rectangle;

	sf::Sprite shape;
	bool drawn;

	std::string name;
	//ensures each box a different name: "box" + namei
	static int namei;
};

Then box’s constructor

1
2
3
4
5
6
7
8
int Box::namei = 1;

Box::Box(){
	name = "box" + std::to_string(namei);
	rectangle.setSize(sf::Vector2f(80, 80));
	rectangle.setPosition(namei * 20, namei * 20);
        namei++;
}

Usage example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Engine::ProcessInput(){
	while(window.pollEvent(event)){
		switch(event.type){
		case sf::Event::Closed:
			window.close();
			break;
		}
		if(sf::Mouse::isButtonPressed(sf::Mouse::Left)){
			sf::Vector2f mouse = window.mapPixelToCoords(sf::Mouse::getPosition(window));
			for(int i = 0; i < board.GetBoxes().size(); i++){
				sf::FloatRect fr = board.GetBoxes()[i].GetRect().getGlobalBounds();
				if(fr.contains(mouse)){
					//do stuff to the box the mouse is inside of
				}
			}

Problem solved, thanks again.

Topic archived. No new replies allowed.

My source code is about as simple as it gets:

#include <set>
#include <string>
#include <functional>
#include <algorithm>
#include <iterator>

using namespace std;

void test() {
    set<string> *S = new set<string>;
    S->insert("hi"); 
    S->insert("lo");
    set<string> *T = new set<string>;
    T->insert("lo");
    set<string> *s = new set<string>;
    set<string>::iterator l=s->begin();
    set_difference(S->begin(),S->end(),T->begin(),T->end(),l);
}

So why do I get a compiler error:

c:program files (x86)microsoft visual studio 10.0vcincludealgorithm(4671): error C2678: binary '=' : no operator found which takes a left-hand operand of type 'const std::basic_string<_Elem,_Traits,_Ax>'

The set «s» is just a set of strings, nothing const there.

asked Apr 4, 2014 at 19:16

the-typist's user avatar

2

You need to use an inserter for the set_difference:

   set_difference(S->begin(),S->end(),T->begin(),T->end(),std::inserter(*s, l))

Building on the comment from Neil Kirk the «exception safe» way of writing this code would be this:

set<string> S;
S.insert("hi"); 
S.insert("lo");
set<string> T;
T.insert("lo");
set<string> s;
set<string>::iterator l=s.begin();
set_difference(S.begin(),S.end(),T.begin(),T.end(),std::inserter(s, l));

In modern C++ there is almost never a case where you need to use new. If you do need to dynamically allocate you should be using unique_ptr or shared_ptr.

answered Apr 4, 2014 at 19:28

pstrjds's user avatar

pstrjdspstrjds

16.7k6 gold badges51 silver badges61 bronze badges

iklepov

1 / 1 / 0

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

Сообщений: 12

1

04.04.2016, 19:54. Показов 1809. Ответов 5

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


Студворк — интернет-сервис помощи студентам

Необходимо из двух multiset вывести совпадающие строки
Написал такой код, но выдает ошибку

C++
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
61
#include "stdafx.h"
#include <vector>
#include <string>
#include <set>
#include <iostream>
#include <fstream>
#include <algorithm>
 
using namespace std;
 
multiset <string> readfile(char *filename);
 
int main(int argc, char *argv[])
{
    multiset <string> first;
    multiset <string> second;
    multiset <string> result;
    setlocale(LC_ALL, "Russian");
    if (argc != 3)
    {
        cout << "Ошибка! Задайте имена файлов!";
    }
    first = readfile(argv[1]);
    second = readfile(argv[2]);
    auto first_begin = first.begin();
    auto first_end = first.end();
    auto second_begin = second.begin();
    auto second_end = second.end();
    auto result_begin = result.begin();
    auto result_end = set_intersection(first_begin, first_end, second_begin, second_end, result_begin);
    for (auto it = result_begin; it != result_end; it++)
    {
        cout << *it << endl;
    }
    system("PAUSE");
    return 0;
}
 
multiset <string> readfile(char *filename)
{
    string temp;
    multiset <string> temp_multiset;
    ifstream file(filename);
    if (!file.is_open())
    {
        cout << "Ошибка открытия файлаn";
    }
    else
    {
        while (!file.eof())
        {
            getline(file, temp);
            if (!temp.empty())
            {
                temp_multiset.insert(temp);
            }
        }
    }
    file.close();
    return temp_multiset;
}

Ошибка C2678 бинарный «=»: не найден оператор, принимающий левый операнд типа «const std::basic_string<char,std::char_traits<char>,std::allocator<char>>» (или приемлемое преобразование отсутствует) lab 2 c:program files (x86)microsoft visual studio 14.0vcincludealgorithm 3649

Ошибка в вызове set_intersection в algorithm
Как можно исправить её?



0



7533 / 6396 / 2916

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

Сообщений: 27,856

04.04.2016, 20:49

2

vector используй.



0



1 / 1 / 0

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

Сообщений: 12

04.04.2016, 20:52

 [ТС]

3

Цитата
Сообщение от nmcf
Посмотреть сообщение

vector используй.

Мне по заданию нужно использовать multiset



0



7533 / 6396 / 2916

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

Сообщений: 27,856

05.04.2016, 13:57

4

Хотя бы результат должен быть в vector. Тогда не используй set_intersection(), пиши свою функцию.



0



avgoor

1550 / 875 / 179

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

Сообщений: 2,555

05.04.2016, 14:27

5

Лучший ответ Сообщение было отмечено iklepov как решение

Решение

Цитата
Сообщение от nmcf
Посмотреть сообщение

Хотя бы результат должен быть в vector.

Не должен.
iklepov, Вместо 30 строки

C++
1
set_intersection(first_begin, first_end, second_begin, second_end, std::inserter(result, result.end());

Не забудь #include <iterator>



2



1 / 1 / 0

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

Сообщений: 12

05.04.2016, 14:58

 [ТС]

6

Все заработало, спасибо большое



0



IT_Exp

Эксперт

87844 / 49110 / 22898

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

Сообщений: 92,604

05.04.2016, 14:58

Помогаю со студенческими работами здесь

set_intersection ??? не понятная ошибка.
есть базовый класс car, производный Bus. Так же есть класс который не связан с Bus и car, он…

Возникает ошибка при компиляции приложения C2678
Вообщем-то всем привет, есть задача сделать приложение, которое сможет отсортировать список, это,…

Ошибки C2678 и C2679 при компиляции кода
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &quot;stdafx.h&quot;
#include &quot;iostream&quot;
#include…

Ошибка при использовании vector (в конце, после вывода результатов выскакивает ошибка, но сам результат коректен)
Суть в следующем, мы считываем введеные значения и выводим этот массив

Проблема такова что…

Ошибка при использовании ADODB.CONNECTION при работе с dbf-файлом
Добрый день! Написала макрос с использованием adodb.connection. макрос удаляет строки из файла dbf….

При использовании кода в модуле ошибка при открытии файла
есть такой простенький код, которій отлично работает в скрипте *.pl

use Cwd;
my $cwd =…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

6

Полная ошибка:

Ошибка 2 ошибка C2678: двоичный файл «==»: не найден оператор, который принимает левый операнд типа «Элемент» (или нет приемлемого преобразования) c: program files (x86) microsoft visual studio 12.0 vc включить алгоритм 1734 1 GameStore


Класс инвентаризации (файл cpp)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <Windows.h>
#include "item.h"
class Inventory
{public:

void Inventory::viewInventory()
{
for (int i = 0; i < inventory.size(); i++)
{
Inventory::inventory[i].getItemName();
}
}

void Inventory::addItem(Item& item)
{
inventory.push_back(item);
}void Inventory::removeItem(Item& item)
{
if (std::find(inventory.begin(), inventory.end(), item) != inventory.end())
{
inventory.erase(std::remove(inventory.begin(), inventory.end(), item), inventory.end());
}

else
{
std::cout << "Item does not exist" << std::endl;
}
}

//Player Gold methods
int Inventory::getGold()
{
return playerGold;
}

void Inventory::setGold(int newGold)
{
playerGold = newGold;
}int Inventory::addGold(int newGold)
{
playerGold += newGold;
return playerGold;
}

int Inventory::removeGold(int newGold)
{
playerGold -= newGold;
return playerGold;
}
//Player Gold methodsprivate:
std::vector<Item> inventory = {};
int playerGold;

};

По сути, я пытаюсь создать систему инвентаризации, в которой хранятся объекты из класса «Предмет». Я потратил много времени на то, чтобы заставить мои циклы for и все мои методы работать, а затем, поскольку небо никогда не было более ясным, я получаю ошибку, из которой выход из моей лиги.


Класс изделия (CPP)

#include "item.h"#include <iostream>
#include <string>Item::Item(int id, std::string name, std::string description, std::string examime)
{
itemName = name;
itemID = id;
itemDescription = description;
itemExamine = examime;

}

void Item::setItemName(std::string newName)
{
itemName = newName;
}

void Item::setItemDescription(std::string newDescription)
{
itemDescription = newDescription;

}

void Item::setItemExamine(std::string newExamine)
{
itemExamine = newExamine;
}

void Item::setItemID(int newID)
{
itemID = newID;
}

std::string Item::getItemName()
{
return itemName;
}

std::string Item::getItemDescription()
{
return itemDescription;
}

std::string Item::getItemExamine()
{
return itemExamine;
}

int Item::getItemID()
{
return itemID;
}

Класс товара (заголовок)

#include <iostream>
#include <string>

class Item
{
public:
//constructor
Item::Item(int id, std::string name, std::string description, std::string examime);

//setters
void setItemName(std::string newName);
void Item::setItemDescription(std::string newDescription);
void Item::setItemExamine(std::string newExamine);
void Item::setItemID(int newID);

//getters
std::string Item::getItemName();
std::string Item::getItemDescription();
std::string Item::getItemExamine();
int Item::getItemID();

private:
std::string itemName;
int itemID;
std::string itemDescription;
std::string itemExamine;

};

Если у вас есть какой-либо совет, даже если это будет переделать всю мою систему, это было бы здорово. Занятия, очевидно, очень просты, и я собираюсь добавить гораздо больше. Это означает, что я не ищу ответ типа «Вам даже не нужен класс предметов»

Спасибо за любую помощь!

0

Решение

Кажется, что основной проблемой вашего кода является отсутствие operator== реализация для вашего Item класс, как говорит ошибка компилятора.

Как новичок в C ++ (не беспокойтесь: каждый из нас был новичком), вы можете спросить Зачем это op== требуется, как вы не называете это эксплицитно в вашем коде. Ну, это правда, что вы не вызываете это явно, но код в стандартной библиотеке реализация Является ли. В частности, вы вызываете std::find (реализовано в<algorithm> заголовок, который цитируется в вашем сообщении об ошибке):

void Inventory::removeItem(...)
{
if (std::find(inventory.begin(), inventory.end(), item) != inventory.end())
{
...

std::find нужно сравнить Item случаи с op==,
Итак, чтобы попытаться исправить ваш код, пожалуйста, определите operator== для сравнения Itemс, как это:

// In the Item class header:

class Item
{
...
};

inline bool operator==(const Item& a, const Item& b)
{
// Implement your comparison logic for Items a and b.
// ...
// Return true if "a == b".
}

В качестве дополнительных примечаний, когда вы объявляете функции-члены внутри вашего класса, вам не нужно использовать Item:: префикс перед функцией-членом:

class Item
{
public:
//constructor
Item::Item(int id, std::string name, std::string description, std::string examime);

//setters
void setItemName(std::string newName);
void Item::setItemDescription(std::string newDescription);
void Item::setItemExamine(std::string newExamine);
void Item::setItemID(int newID);
...

Просто делать:

class Item
{
public:
//constructor
Item(int id, std::string name, std::string description, std::string examime);

//setters
void setItemName(std::string newName);
void setItemDescription(std::string newDescription);
void setItemExamine(std::string newExamine);
void setItemID(int newID);

...

Кроме того, рассмотрите возможность создания ваших добытчиков const, чтобы сделать ваш класс const-правильным, например:

   class Item
{
public:
...
std::string getItemName() const;
std::string getItemDescription() const;
std::string getItemExamine() const;
int getItemID() const;

...
};

2

Другие решения

Других решений пока нет …

Понравилась статья? Поделить с друзьями:
  • Ошибка компиляции для платы arduino mega
  • Ошибка компилятора c2665
  • Ошибка компиляции для платы arduino leonardo как исправить
  • Ошибка компилятора c2614
  • Ошибка компиляции для платы arduino genuino uno