I have a list of Text Editors that is to be rendered on the application whenever the user selected a file. It works well however when I started to delete elements on the list to signify that they were closed by the user and not to be rendered again, the problem starts to arise when I selected that same file that was deleted earlier to have a duplicate. So, I was trying to remove the duplicates by first sorting the list and then use std::unique before rendering.
Here's the part where I render the text editors
if(!Opened_TextEditors.empty())
{
std::sort(Opened_TextEditors.begin(), Opened_TextEditors.end());
auto last = std::unique(Opened_TextEditors.begin(), Opened_TextEditors.end());
Opened_TextEditors.erase(last, Opened_TextEditors.end());
auto it = Opened_TextEditors.begin();
while(it != Opened_TextEditors.end())
{
if(it->IsWindowVisible())
{
it->Render();
if(it->IsWindowFocused()){
char buffer[255];
selected_window_path = it->GetPath(); // determines which window is active or currently selected. For writing contents on status bar
selected_editor_path = it->GetPath(); // This is to deterimine which window is focused or currently selected. For determining where to render the next selected window. This is to reduce reordering during rendering.
auto cpos = it->GetCursorPosition();
snprintf(buffer, sizeof(buffer), "Ln %d, Col %-6d %6d lines | %s | %s | %s | %s ", cpos.mLine + 1, cpos.mColumn + 1, it->GetTotalLines(),
it->IsOverwrite() ? "Ovr" : "Ins",
it->CanUndo() ? "*" : " ",
it->GetFileExtension().c_str(),
it->GetFileName().c_str()
);
current_editor = std::string(buffer);
}
++it;
}
else {//Bug: When the editor was deleted and is selected again to be rendered, causes some sort of anomalies where it tends not being docked and somtimes when it was rendered and tried to close any window, every window will be deleted.
it = Opened_TextEditors.erase(it);
}
}
}
And here's the part where I add the selected text editor
auto it = std::find(Opened_TextEditors.begin(), Opened_TextEditors.end(), parentNode.FullPath);
if(it == Opened_TextEditors.end())
{
static unsigned int id = 0;
ArmSimPro::TextEditor editor(parentNode.FullPath, id,bg_col.GetCol());
auto programming_lang = ArmSimPro::TextEditor::LanguageDefinition::CPlusPlus();
++id;
for (int i = 0; i < sizeof(ppnames) / sizeof(ppnames[0]); ++i)
std::future<void> PreprocIdentifier = std::async(std::launch::async, SetupPreprocIdentifiers, programming_lang, ppvalues[i]);
for (int i = 0; i < sizeof(identifiers) / sizeof(identifiers[0]); ++i)
std::future<void> Identifiers = std::async(std::launch::async, SetupIdentifiers, programming_lang, identifiers[i], idecls[i]);
editor.SetLanguageDefinition(programming_lang);
std::ifstream t(parentNode.FullPath.c_str());
if (t.good())
{
std::string str;
t.seekg(0, std::ios::end);
str.reserve(t.tellg());
t.seekg(0, std::ios::beg);
str.assign((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
editor.SetText(str);
}
if(!selected_editor_path.empty()){
int index = GetTextEditorIndex(selected_editor_path) + 1;
Opened_TextEditors.insert(Opened_TextEditors.begin() + index, editor);
}
if(Opened_TextEditors.empty())
Opened_TextEditors.push_back(editor);
}
When I run it, it gives an error message:
call to object of class type 'std::less<void>': no matching call operator found
call to object of class type 'std::less<void>': no matching call operator found
So, I added an function on my class that overloads the "==" operator:
class TextEditor
{
public:
.....
bool operator==(TextEditor& other) { return this->path == other.path; }
bool operator==(const TextEditor& other) { return this->path == other.path; }
bool operator==(const std::string& full_path) const { return this->path == full_path; }
.....
};
I don't have much of experience in <algorithm>
since I was just starting to learn for a few months but I suspect the error was coming from std::unique
. I've found this similar problem but still get the same error. Is there anything that I could add on my TextEditor
class to satisfy the parameters on the std::unique
?
At this problem I've seen people saying to use std::set
to avoid duplicates. However, to allow adding text editors next to the current selected text editor need an ability to insert at a particular index. This is done by searching through the list and finds the editor that has the specified file path and then get its position.
The error more than likely is coming from std::sort
and not std::unique
. The 2-argument std::sort
requires that the type can be compared with <
, which TextEditor
does not have.
I would use the 3-argument std::sort
that allows a predicate to be used, instead of having to provide an overloaded operator <
to the TextEditor
class.
Here is a full example:
#include <vector>
#include <iostream>
#include <algorithm>
class TextEditor
{
std::string path;
public:
TextEditor(const char * p) : path(p) {}
const std::string& getPath() const { return path;}
};
int main()
{
std::vector<TextEditor> v;
v.push_back("path1");
v.push_back("path2");
v.push_back("path1"); // Duplicate
std::sort(v.begin(), v.end(), [](const TextEditor& e1, const TextEditor& e2)
{ return e1.getPath() < e2.getPath(); });
auto it = std::unique(v.begin(), v.end(), [](const TextEditor& e1, const TextEditor& e2)
{ return e1.getPath() == e2.getPath(); });
v.erase(it, v.end());
for (auto& te : v)
{
std::cout << te.getPath() << "\n";
}
}
Output:
path1
path2
Note that the 3-argument std::unique
call was made, thus not needing to write an overloaded operator==
.