Error C2678: binary "<"

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.0\vc\include\xstddef 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:\users\jordan\documents\visual studio 2012 \projects\tictactoe\tictactoe\board.cpp 23 1 TicTacToe
Warning 2 warning C4244: 'argument' : conversion from 'int' to 'float', possible loss of data c:\users\jordan\documents\visual studio 2012\projects\tictactoe\tictactoe\board.cpp 25 1 TicTacToe
Warning 3 warning C4018: '<' : signed/unsigned mismatch c:\users\jordan\documents\visual studio 2012\projects\tictactoe\tictactoe\board.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.0\vc\include\xstddef 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.0\vc\include\xstddef(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:\users\ben\c++ libs\sfml-2.0\include\sfml\system\time.hpp(185): could be 'bool sf::operator <(sf::Time,sf::Time)' [found using argument-dependent lookup]
1>          c:\users\ben\c++ libs\sfml-2.0\include\sfml\system\string.hpp(398): or       'bool sf::operator <(const sf::String &,const sf::String &)' [found using argument-dependent lookup]
1>          c:\users\ben\c++ libs\sfml-2.0\include\sfml\window\videomode.hpp(141): or       'bool sf::operator <(const sf::VideoMode &,const sf::VideoMode &)' [found using argument-dependent lookup]
1>          c:\users\ben\c++ libs\sfml-2.0\include\sfml\network\ipaddress.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.0\vc\include\xstddef(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.0\vc\include\map(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.0\vc\include\type_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.0\vc\include\xtree(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.0\vc\include\map(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:\users\ben\documents\visual studio 2012\projects\wxtimetest\main.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:\users\jordan\documents\visual studio 2012\projects\tictactoe\tictactoe\board.cpp(23): warning C4018: '<' : signed/unsigned mismatch
1>c:\users\jordan\documents\visual studio 2012\projects\tictactoe\tictactoe\board.cpp(31): warning C4018: '<' : signed/unsigned mismatch
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstddef(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.1\include\sfml\system\time.hpp(185): could be 'bool sf::operator <(sf::Time,sf::Time)' [found using argument-dependent lookup]
1>          c:\program files (x86)\sfml-2.1\include\sfml\system\string.hpp(398): or       'bool sf::operator <(const sf::String &,const sf::String &)' [found using argument-dependent lookup]
1>          c:\program files (x86)\sfml-2.1\include\sfml\window\videomode.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.0\vc\include\xstddef(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.0\vc\include\map(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.0\vc\include\type_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.0\vc\include\xtree(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.0\vc\include\map(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:\users\jordan\documents\visual studio 2012\projects\tictactoe\tictactoe\board.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:\users\jordan\documents\visual studio 2012\projects\tictactoe\tictactoe\board.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.0\vc\include\xtree 1319 1 TicTacToe
Error 3 error C2100: illegal indirection c:\program files (x86)\microsoft visual studio 11.0\vc\include\xtree 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.