C++ std::find lambda expressions - c++

For the life of me, I cannot get this code to work. I'm attempting to convert my code from C# to C++ following the deprecation of the XNA framework, but a stubborn method does not want to be converted. In C# it is:
public Tile GetTileAtPosition(bool screenOrGame, Vector2 position)
{
if (screenOrGame)
{
return Array.Find(tileList, tile => tile.Position == position / 24);
}
else
{
return Array.Find(tileList, tile => tile.Position == position);
}
}
In C++, the code I'm attempting to use in place of this is:
Tile Level::GetTileAtPosition(bool screenOrGame, sf::Vector2f position)
{
vector<Tile>::iterator it;
if (screenOrGame)
{
it = find(tileList.begin(), tileList.end(), [position](const Tile &t) { return t.GetPosition() == sf::Vector2f(position.x / 24, position.y / 24); });
return Tile(it->GetID(), it->GetPosition().x, it->GetPosition().y);
}
else
{
it = find(tileList.begin(), tileList.end(), [position](const Tile& t) { return t.GetPosition() == position; });
return Tile(it->GetID(), it->GetPosition().x, it->GetPosition().y);
}
}
On the C++ assignment lines (it = ...) I am getting a painstaking error that I cannot figure out the cause of, or a solution for. It returns:
error C2679: binary '==' : no operator found which takes a right-hand operand of type 'const Blobby::Level::GetTileAtPosition::<lambda_29eb981cd341d9c05d39c4654bc470b9>' (or there is no acceptable conversion) c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility 3186
Is there any way to fix this error, or a better/more practical way to implement the method in C++?

In C++, the versions taking a comparator are sometimes suffixed with _if. This is the case for std::find. std::find takes an element to find, whereas std::find_if takes a comparator that implements equality. The error simply means that it couldn't find a match for a Tile being equivalent to a lambda.

Related

MSVC (std:c++17) Optional always returning a value

I'm writing some intersection code for a Ray tracer. After calculating some intersection logic for a sphere, I want to return an optional to determine if there was an intersection or not. Instead of returning an "invalid" value for distance, I want to use C++'s std::optional class. The only issue is that it seems to always return true for has_value():
std::optional<Intersection> Sphere::ray_intersection(Ray ray)
// Calculate Intersection Logic
// ...
if (distance_to_intersection < 0) {
return std::nullopt;
} else {
return Intersection(ray, distance_to_intersection);
}
}
After returning, I check using the following code:
if (sphere.ray_intersection(ray).has_value()) {
return shade(sphere, intersection);
} else {
return background_color;
}
I know the actual intersection logic works correctly, because when I replace return std::nullopt; with return Intersection(ray, -1); (an invalid distance) and then simply check if the distance is equal to -1 in the previous if check, it behaves as expected.
I've also tried returning a simple {} to no avail.
I'm currently using Microsoft Visual Studio 2022, and I have tried both the C++17 and C++20 compilers, and neither will behave as I'm expecting.
Is there a specific way that std::optional operates that I'm not aware of?

Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'T'

I try to compile the following code:
class CFileOperations
{
...
template <typename T>
inline void load_and_save_data(std::fstream* stream, T& value, const EOperation operation)
{
switch (operation) {
case EOperation::OpSave:
*stream << value; <-- here
break;
case EOperation::OpLoad:
*stream >> value; <-- and here
break;
}
}
...
};
I get the following errors:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)
Error C2679 binary '>>': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)
For example, I use it this way, with number being an 'int':
this->load_and_save_data(stream, number, operation);
I'm using Visual C++ 2019.
What's the root cause, and how to solve it. Any idea ?
My bad, one of the calls was with a 'class enum'. Of course, >> and << are not defined for it.
For #cdhowie, here are two examples of the resulting simplicity (with the help of load_and_save_data template methods):
Here mMembers is a std::unorderedmap (cf. save_and_load_data in the question above, I have also one for the starndard containers):
void CHexArea::load_and_save()
{
this->load_and_save_data((char&)mColor);
this->load_and_save_data(mTouchLeft);
this->load_and_save_data(mTouchRight);
this->load_and_save_data(mTouchBottom);
this->load_and_save_data(mTouchTop);
this->load_and_save_data(mMembers);
}
Here, in preferences, there are two versions of files:
void CHexPreferences::load_and_save()
{
if( this->is_loading() ) {
this->reset(); // version's forward compatibility
}
int version = 2;
this->load_and_save_data(version);
this->load_and_save_data(mBoardOrientation);
this->load_and_save_data(mBoardSize);
this->load_and_save_data(mComputerStarts);
this->load_and_save_data(mComputerInitialTurns);
if( version >= 2) {
this->load_and_save_data(mComputerTilesPerTurn);
}
this->load_and_save_data(mDebugFlags);
}
Simple and clear.
Of course, there are two methods (load() and save()) that are the outer interface and calls those here above, but: 1. They are part of a library (no need to rewrite them, OO as usual) and 2. The core of the load/save is written only once in load_save_data, with the advantage of simplicity, and having corresponding load and save code (types, order...).
Of course, there are cons, but I hope you'll see that it may make sense for some people to think that there are (IMHO very strong) pros as well.
The rest is a matter of taste.

How can I retrieve a specific member from a class with a getter inside of a function that uses an iterator inside of a loop?

I'm trying to make a function that returns a class (CTaxGroup) by taking as parameter a TaxGroupId.
The function will loop through a vector with an iterator.
int m_TaxGroupId;
CTaxGroup CTaxGroupVector::FetchTaxGroup(int TaxGroupId)
{
CTaxGroup l_TaxGroup;
std::vector<CTaxGroup>::iterator l_iterator =m_TaxGroupVector.begin();
for(l_iterator; l_iterator != m_TaxGroupVector.end(); l_iterator++)
{
int l_TaxGroupId = *l_iterator->GetTaxGroupId();
if(l_TaxGroupId == TaxGroupId)
{
l_TaxGroup = *l_iterator;
}
}
return l_TaxGroup;
}
std::vector<CTaxGroup> CTaxGroupVector::GetTaxGroupVector()
{
return m_TaxGroupVector;
}
At line 7, I get an error from my IDE (RAD Studio XE4) which states :
"E2062 Invalid indirection".
I know that it was something to do with the pointer, but I'm not sure what is my error.
I'm expecting that line 7 would return me an integer.
Without testing, since you don't provide a compilable program, it's likely that you should put parentheses around the initial dereferencing, (*l_iterator)->GetTaxGroupId(), so that the compiler knows you're trying to access a member of a CTaxGroup, not a member of an iterator.

how to convert map into set

i got some issues trying to convert my map into a set
I got a "Chanson" object with this member data :
std::map<std::string,Artiste*> m_interpretes;
Here is how i add my *Artiste to my map :
void Chanson::addArtiste(Artiste* a) throw (ExceptionArtiste, ExceptionLangueIncompatible)
{
if(a!=NULL)
{
if(a->getLangue() == this->getLangue())
{
m_interpretes.insert(pair<string, Artiste*>(a->getNom(), a));
//m_interpretes[a->getNom()] = a;
}
else
{
throw ExceptionLangueIncompatible(a,this);
}
}
}
set<Artiste*> Chanson::getArtistes() const
{
//set<Artiste*> machin;
return set<Artiste*> (m_interpretes.begin(), m_interpretes.end());
}
i got this error due to this function :
Error C2664: 'std::pair<_Ty1,_Ty2> std::set<_Kty>::insert(Artiste *&&) : impossible de convertir le paramètre 1 de const std::pair<_Ty1,_Ty2> en 'Artiste *&&' c:\program files (x86)\microsoft visual studio 11.0\vc\include\set 179 1
Any idea how to fix it?
A map is an associative data structure, while a set only contains unordered collection of items, so adding a pair (key, value) is invalid for the latter and only holds for the former.
To make a set of keys from a map, you can do
std::set<Artiste*> tempSet;
std::transform(m_interpretes.cbegin(), m_interpretes.cend(),
std::inserter(tempSet, tempSet.begin()),
[](const std::pair<std::string, Artiste*>& key_value)
{ return key_value.second; });
return tempSet;
The std::set constructor you are trying to use will try to construct an element from everything the range you pass it:
return set<Artiste*> (m_interpretes.begin(), m_interpretes.end());
But the element type of that range is
std::pair<const std::string, Artiste*>
which is definitely not convertible to Artiste*, which is why you are getting that error about not being able to convert. You could just do it manually though:
std::set<Artiste*> s;
for (const auto& pair : m_interpretes) {
s.insert(pair.second);
}
The problem is here:
return set<Artiste*> (m_interpretes.begin(), m_interpretes.end());
If you have a look at the types you get from the map::begin() and map::end() functions you see that you get an iterator of std::pair<string, Artiste*>.
The problem is that the set::insert() function expects the iterators it is given to be of type Artiste*.
The simplest fix would be to create the set with a for loop, as shown in Barry's answer.

C2678 error on remove from list of custom datatypes

I'm currently hard at work on an assignment piece, which contains several custom datatypes. I've run into a problem where list is complaining that I am trying to remove a custom data type from a list of that same data type.
Error 3 error C2678: binary '==' : no operator found which takes a left-hand operand of type 'customer' (or there is no acceptable conversion) c:\program files (x86)\microsoft visual studio 10.0\vc\include\list 1194 1 Assignment 1 - Video Store MIS
The relevant code is here:
void customerCollection::removeCustomer(customer person)
{
customers.remove(person);
}
and the custom data type does have a == operator defined:
bool customer::operator==(customer &other) const
{
return (l_fullName == other.getName()) &&
(l_contactNumber == other.getNumber()) &&
(l_password == other.getPassword()) &&
(l_username == other.getUsername());
}
Is there any reason that the list type can't see the overloaded operator?
The customerCollection and customer data types are required parts of the program.
[EDIT] The overloaded operator is defined as public in the header file.
bool customer::operator==(customer &other) const
Try changing that to
bool customer::operator==(const customer &other) const
It is possible the code of the customers collection passes a const-qualified customer to the equality operator. At least, it is more idiomatic (and logical).
I'm inclined to say the reason is that the parameter is not const:
bool customer::operator==(const customer& other) const
depending on how remove is defined.