Creating an unindent algorithm using boost::range - c++

I'm creating an unindent algorithm for a text-editor. I've managed to obtain the range to operate on, but when I want to do the Gtk::TextBuffer::erase, it fails:
void unindentSelection(const Glib::RefPtr<Gtk::TextBuffer> &buffer)
{
Gtk::TextBuffer::iterator start, end;
buffer->get_selection_bounds(start, end);
auto selRange = boost::make_iterator_range(start, end);
auto buffRange = boost::make_iterator_range(buffer->begin(), buffer->end());
auto prevRangeRev = boost::make_iterator_range(buffRange.begin(), selRange.begin()) | boost::adaptors::reversed;
auto prevRangeLineRev = boost::find<boost::return_begin_found>(prevRangeRev, '\n');
auto prevRangeLine = prevRangeLineRev | boost::adaptors::reversed;
auto afterRange = boost::make_iterator_range(selRange.end(), buffRange.end());
auto afterRangeLine = boost::find<boost::return_begin_found>(afterRange, '\n');
auto exSelRangeAux = boost::join(prevRangeLine, selRange);
auto exSelRange = boost::join(exSelRangeAux, afterRangeLine);
show_range(exSelRange);
while (true)
{
auto spaceRange = boost::find_if<boost::return_begin_found>(exSelRange, findNonspaceNL);
if (boost::distance(spaceRange))
{
buffer->erase(spaceRange.begin(), spaceRange.end());
}
}
}
TextEditor.cpp:501:31: error: no viable conversion from 'boost::range_detail::join_iterator >, Gtk::TextIter, unsigned int, unsigned int, boost::iterators::bidirectional_traversal_tag>, Gtk::TextIter, unsigned int, unsigned int, boost::iterators::bidirectional_traversal_tag>' to 'const iterator' (aka 'const Gtk::TextIter')
buffer->erase(spaceRange.begin(), afterRangeLine.end());
^~~~~~~~~~~~~~~~~~
/usr/include/gtkmm-3.0/gtkmm/textiter.h:145:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'boost::range_detail::join_iterator >, Gtk::TextIter, unsigned int, unsigned int, boost::iterators::bidirectional_traversal_tag>, Gtk::TextIter, unsigned int, unsigned int, boost::iterators::bidirectional_traversal_tag>' to 'const Gtk::TextIter &' for 1st argument
class TextIter
^
/usr/include/gtkmm-3.0/gtkmm/textiter.h:145:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'boost::range_detail::join_iterator >, Gtk::TextIter, unsigned int, unsigned int, boost::iterators::bidirectional_traversal_tag>, Gtk::TextIter, unsigned int, unsigned int, boost::iterators::bidirectional_traversal_tag>' to 'Gtk::TextIter &&' for 1st argument
class TextIter
^
/usr/include/gtkmm-3.0/gtkmm/textbuffer.h:378:34: note: passing argument to parameter 'range_begin' here
iterator erase(const iterator& range_begin, const iterator& range_end);
Any ideas?

I had to create an iterator type that contained a templated 'Iterator it' inside (which in my case is the Gtk::TextIter), using 'boost::iterator_facade'. All operations to the iterator where forwarded to 'it', except the operator*(), that just gave the plain iterator. So the erasing was done in this way:
buffer->erase(*spaceRange.begin(), *spaceRange.end());
This new type of iterator will be very useful manipulating ranges. Not sure this is the best solution, but works.

Related

Issue regarding inheritance - "type is not a base class"

I'm trying to create a functional inheritance hierarchy. We are working with implementing our own priority queue class template, and the program includes lists such as buy orders.
My idea was to have "p_queue" as the base class, and let the "orders" class inherit from it, and then let subclasses such as "buy_orders" inherit from the orders class. My reasoning is that every order in this program is a priority queue, as they will be sorted by it.
Normally I would understand the error "type 'base_class' is not a direct base of 'sub_class'" if the derived class wasn't directly inheriting the superclass. But since the orders class inherits the p_queue class and no other class directly inherits from priority queue class, I'm confused why I get this error message.
Here is the code
//main.cpp
#include "orders.h"
int main(){
return 0;
}
//orders.h
#include "p_queue.h"
template<typename T>
struct less{
bool operator()(const T& a, const T& b){
return a < b;
}
};
template<typename T>
class Orders : public p_queue<T, decltype(less<T>())> {
private:
size_t m_Size;
std::vector<T> list;
public:
Orders(const size_t& sz, const std::vector<T>& l) : list(l), m_Size(sz),
p_queue<T>(&(*list.begin()), &(*list.end()), less<T>()){}
virtual const size_t getSize() const { return m_Size; }
virtual const std::vector<T> getList() const = 0;
};
struct buy_orders : public Orders<size_t>{
std::vector<size_t> buy_prices;
buy_orders(const size_t& sz) : Orders(sz, buy_prices) {}
};
//p_queue.h
#include <functional>
template<typename T, typename Compare = std::less<T>>
class p_queue{
protected:
T* m_first;
T* m_last;
Compare m_comp;
public:
p_queue(T* first, T* last, Compare comp = Compare()) :
m_first(first), m_last(last), m_comp(comp) {}
};
The above code produces the error:
<source>: In instantiation of 'Orders<T>::Orders(const size_t&, const std::vector<T>&) [with T = long unsigned int; size_t = long unsigned int]':
<source>:39:57: required from here
<source>:31:59: error: type 'p_queue<long unsigned int, std::less<long unsigned int> >' is not a direct base of 'Orders<long unsigned int>'
31 | p_queue<T>(&(*list.begin()), &(*list.end()), less<T>()){}
| ^
<source>:31:59: error: no matching function for call to 'p_queue<long unsigned int, less<long unsigned int> >::p_queue()'
<source>:13:5: note: candidate: 'p_queue<T, Compare>::p_queue(T*, T*, Compare) [with T = long unsigned int; Compare = less<long unsigned int>]'
13 | p_queue(T* first, T* last, Compare comp = Compare()) :
| ^~~~~~~
<source>:13:5: note: candidate expects 3 arguments, 0 provided
<source>:7:7: note: candidate: 'constexpr p_queue<long unsigned int, less<long unsigned int> >::p_queue(const p_queue<long unsigned int, less<long unsigned int> >&)'
7 | class p_queue{
| ^~~~~~~
<source>:7:7: note: candidate expects 1 argument, 0 provided
<source>:7:7: note: candidate: 'constexpr p_queue<long unsigned int, less<long unsigned int> >::p_queue(p_queue<long unsigned int, less<long unsigned int> >&&)'
<source>:7:7: note: candidate expects 1 argument, 0 provided
ASM generation compiler returned: 1
<source>: In instantiation of 'Orders<T>::Orders(const size_t&, const std::vector<T>&) [with T = long unsigned int; size_t = long unsigned int]':
<source>:39:57: required from here
<source>:31:59: error: type 'p_queue<long unsigned int, std::less<long unsigned int> >' is not a direct base of 'Orders<long unsigned int>'
31 | p_queue<T>(&(*list.begin()), &(*list.end()), less<T>()){}
| ^
<source>:31:59: error: no matching function for call to 'p_queue<long unsigned int, less<long unsigned int> >::p_queue()'
<source>:13:5: note: candidate: 'p_queue<T, Compare>::p_queue(T*, T*, Compare) [with T = long unsigned int; Compare = less<long unsigned int>]'
13 | p_queue(T* first, T* last, Compare comp = Compare()) :
| ^~~~~~~
<source>:13:5: note: candidate expects 3 arguments, 0 provided
<source>:7:7: note: candidate: 'constexpr p_queue<long unsigned int, less<long unsigned int> >::p_queue(const p_queue<long unsigned int, less<long unsigned int> >&)'
7 | class p_queue{
| ^~~~~~~
<source>:7:7: note: candidate expects 1 argument, 0 provided
<source>:7:7: note: candidate: 'constexpr p_queue<long unsigned int, less<long unsigned int> >::p_queue(p_queue<long unsigned int, less<long unsigned int> >&&)'
<source>:7:7: note: candidate expects 1 argument, 0 provided
If I remove the buy_orders struct from orders.h, the problem disappears. Why is this? How can I solve this issue?
You actually have 2 problems here.
First one is simply that you have to pass explicitely the second template parameter to the p_queue constructor:
...
Orders(const size_t& sz, const std::vector<T>& l) : list(l), m_Size(sz),
p_queue<T, decltype(less<T>())>(&(*list.begin()), &(*list.end()), less<T>()) {}
...
is enough to make the type 'base_class' is not a direct base of 'sub_class' error disappear.
But there is still another problem, even if it only raises a warning. Base classes are initialized before data members in C++, no matter the order of initializers. That means that p_queue constructor will be called before initialization of list, leading to Undefined Behaviour, because it explicitely uses the first and last members before they get a chance to be initialized. That means that you have to set up a 2 phases initialization of p_queue, with a default initialization first, and then set its m_first and m_last members in Orders constructor body:
...
p_queue(Compare comp = Compare()) : m_comp(comp) {}
p_queue(T* first, T* last, Compare comp = Compare()) :
m_first(first), m_last(last), m_comp(comp) {}
...
and
...
Orders(const size_t& sz, const std::vector<T>& l) : list(l), m_Size(sz),
p_queue<T, decltype(less<T>())>(less<T>()) {
this->m_first = &(*list.begin());
this->m_last = &(*list.end());
}
...
Problem 1
The problem is that p_queue<T> and p_queue<T, decltype(::less<T>())> are two different class-type and you're inheriting from the latter(p_queue<T, decltype(::less<T>())>) but trying to use the constructor of the former(p_queue<T>) in the member initializer list.
To solve this just make sure that you use the constructor of p_queue<T, decltype(::less<T>())> instead of p_queue<T> in the member initializer list as shown below:
template<typename T>
class Orders : public p_queue<T, decltype(::less<T>())> {
private:
size_t m_Size;
std::vector<T> list;
public:
Orders(const size_t& sz, const std::vector<T>& l) : list(l), m_Size(sz),
//--------------vvvvvvvvvvvvvvvvvvvv---->added this second template argument
p_queue<T , decltype(::less<T>())>(&(*list.begin()), &(*list.end()), ::less<T>()){}
virtual const size_t getSize() const { return m_Size; }
virtual const std::vector<T> getList() const = 0;
};
Working demo
Problem 2
Additionally as base class ctor will be used before the derived class member like list is initialized, and since you're using *list.begin() as an argument to the base class ctor, the program has undefined behavior.
Clang gives a warning about this:
<source>:36:43: warning: field 'list' is uninitialized when used here [-Wuninitialized]
p_queue<T , decltype(::less<T>())>(&(*list.begin()), &(*list.end()), ::less<T>()){}
^
<source>:44:36: note: in instantiation of member function 'Orders<unsigned long>::Orders' requested here
buy_orders(const size_t& sz) : Orders(sz, buy_prices) {}
^
<source>:36:61: warning: field 'list' is uninitialized when used here [-Wuninitialized]
p_queue<T , decltype(::less<T>())>(&(*list.begin()), &(*list.end()), ::less<T>()){}

Type mismatch when using unordered_map with Catch2 Predicate

Catch2 gives a Predicate class to make our own matcher. https://github.com/catchorg/Catch2/blob/master/docs/matchers.md
I simply test an unordered_map(decltype(getEntity2IdMap()) here.
namespace Generic {
Predicate<decltype(getEntity2IdMap())>(
[&](auto& maps) -> bool {
return maps.size() == 3 &&
maps["entity1"] == 0 &&
maps["entity2"] == 1 &&
maps["entity3"] == 2; },
"entities were inserted."));
The Predicate class has a simple definition.
template <typename T>
class PredicateMatcher : public MatcherBase<T> {
std::function<bool(T const&)> m_predicate;
std::string m_description;
public:
PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
:m_predicate(std::move(elem)),
m_description(Detail::finalizeDescription(descr))
{}
bool match( T const& item ) const override {
return m_predicate(item);
}
std::string describe() const override {
return m_description;
}
};
} // namespace Generic
// The following functions create the actual matcher objects.
// The user has to explicitly specify type to the function, because
// infering std::function<bool(T const&)> is hard (but possible) and
// requires a lot of TMP.
template<typename T>
Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
return Generic::PredicateMatcher<T>(predicate, description);
}
However, clang++ yields a type mismatch.
error: no viable overloaded operator[] for type 'const std::__1::unordered_map<std::__1::basic_string<char>,
unsigned int, std::__1::hash<std::__1::basic_string<char> >, std::__1::equal_to<std::__1::basic_string<char> >,
std::__1::allocator<std::__1::pair<const std::__1::basic_string<char>, unsigned int> > >'
I am wondering the maps type here or I misunderstood the lambda context for "/m/entity1".
The full error message is likely to be something like:
<source>:7:21: error: no viable overloaded operator[] for type 'const std::unordered_map<std::string, int>' (aka 'const unordered_map<basic_string<char>, int>')
std::cout << map["test" ] == 1;
~~~^~~~~~~
unordered_map.h:963:7: note: candidate function not viable: 'this' argument has type 'const std::unordered_map<std::string, int>' (aka 'const unordered_map<basic_string<char>, int>'), but method is not marked const
operator[](const key_type& __k)
^
unordered_map.h:967:7: note: candidate function not viable: 'this' argument has type 'const std::unordered_map<std::string, int>' (aka 'const unordered_map<basic_string<char>, int>'), but method is not marked const
operator[](key_type&& __k)
The key clue is 'this' argument has type 'const.... but method is not marked const.
Your maps are const but operator[] is not const, you need to use find() or at() to retrieve values from a const std::map or std::unordered_map.

Template deduction vs. implicit user-defined conversion operator

I tried to implement a little example of user-defined type conversion involving templates.
#include <cassert>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <type_traits>
template <typename T>
concept bool UIntegral = requires() {
std::is_integral_v<T> && !std::is_signed_v<T>;
};
class Number
{
public:
Number(uint32_t number): _number(number)
{
if (number == 1) {
number = 0;
}
for (; number > 1; number /= 10);
if (number == 0) {
throw std::logic_error("scale must be a factor of 10");
}
}
template <UIntegral T>
operator T() const
{
return static_cast<T>(this->_number);
}
private:
uint32_t _number;
};
void changeScale(uint32_t& magnitude, Number scale)
{
//magnitude *= scale.operator uint32_t();
magnitude *= scale;
}
int main()
{
uint32_t something = 5;
changeScale(something, 100);
std::cout << something << std::endl;
return 0;
}
I get the following compilation error (from GCC 7.3.0):
main.cpp: In function ‘void changeScale(uint32_t&, Number)’:
main.cpp:40:15: error: no match for ‘operator*=’ (operand types are ‘uint32_t {aka unsigned int}’ and ‘Number’)
magnitude *= scale;
Notice the line commented out - this one works:
//magnitude *= scale.operator uint32_t();
Why can't the templated conversion operator be automatically deduced? Thanks in advance for help.
[EDIT]
I followed the advice of removing concepts to use Clang and see its error messages. I got the following (this is truncated but sufficient):
main.cpp:34:15: error: use of overloaded operator '*=' is ambiguous (with operand types 'uint32_t'
(aka 'unsigned int') and 'Number')
magnitude *= scale;
~~~~~~~~~ ^ ~~~~~
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, float)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, double)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, long double)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, __float128)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, int)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, long long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, __int128)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned int)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned __int128)
So, having the concepts turned on I assume that the only way to cast a Number is to do it to an unsigned integral type - then why is it insufficient for the compiler to deduce the conversion?
The requires concept expression works like SFINAE, it only checks that the expression is valid, but does not evaluate it.
To have the concept actually restrict T to an unsigned integral type, use a bool expression:
template<typename T>
concept bool UIntegral = std::is_integral_v<T> && !std::is_signed_v<T>;
Will that fix your issue though? Unfortunately not, read on...
Why can't the templated conversion operator be automatically deduced?
Writing buggy C++ code is a sure way to hit a compiler bug :-) There are over 1,000 confirmed unresolved bugs in gcc.
Yes the templated conversion operator should be found, and the "no match for 'operator*='" error message should be instead "ambiguous overload for 'operator*='".
So, having the concepts turned on I assume that the only way to cast a Number is to do it to an unsigned integral type - then why is it insufficient for the compiler to deduce the conversion?
Even if the concept requirement and the compiler bug were fixed, the ambiguity will remain, specifically these four:
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned int)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned long long)
main.cpp:34:15: note: built-in candidate operator*=(unsigned int &, unsigned __int128)
That's because there are a lot of built-in operators for every conceivable promoted built-in type, and int, long, long long and __int128 are all integral types.
For that reason it's usually not a good idea to templatize a conversion to a built-in type.
Solution 1. Make the conversion operator template explicit and request the conversion explicitly
magnitude *= static_cast<uint32_t>(scale);
// or
magnitude *= static_cast<decltype(magnitude)>(scale);
Solution 2. Just implement a non-templated conversion to the type of _number:
struct Number
{
using NumberType = uint32_t;
operator NumberType () const
{
return this->_number;
}
NumberType _number;
};

Method with const parameter does not accept non-const parameter?

This code does not compile:
ErrorTolerantSearch e;
e.readStringsFromFile("test.txt");
e.buildQgramIndex(3);
vector<map<uint, uint>*> lists;
lists.push_back(&e._qgramIndex["ret"]); // ignore this, assume container not empty
lists.push_back(&e._qgramIndex["coo"]); // ignore this, assume container not empty
map<uint, uint> resunion = e.computeUnion(lists); // <-- this makes problems
This is a part of the header
class ErrorTolerantSearch {
public:
void readStringsFromFile(string fileName);
void buildQgramIndex(uint q);
map<uint, uint> computeUnion(const vector<const map<uint, uint>*> & lists);
map<string, map<uint, uint> > _qgramIndex;
};
This is the error the compiler gives:
ErrorTolerantSearchTest.cpp: In member function ‘virtual void ErrorTolerantSearchTest_computeUnion_Test::TestBody()’:
ErrorTolerantSearchTest.cpp:89:50: error: no matching function for call to ‘ErrorTolerantSearch::computeUnion(std::vector<std::map<unsigned int, unsigned int>*>&)’
ErrorTolerantSearchTest.cpp:89:50: note: candidate is:
In file included from ErrorTolerantSearchTest.cpp:36:0:
./ErrorTolerantSearch.h:56:19: note: std::map<unsigned int, unsigned int> ErrorTolerantSearch::computeUnion(const std::vector<const std::map<unsigned int, unsigned int>*>&)
./ErrorTolerantSearch.h:56:19: note: no known conversion for argument 1 from ‘std::vector<std::map<unsigned int, unsigned int>*>’ to ‘const std::vector<const std::map<unsigned int, unsigned int>*>&’
make[1]: *** [ErrorTolerantSearchTest] Fehler 1
But what is the problem? I dont get it. I never had problems with passing non-const variables to functions with const parameters by reference.
std::vector<const T> is not equal to std::vector<T> and no convertible to it.

Is it possible to alias boost::make_iterator_range?

I am having trouble aliasing the function boost::make_iterator_range
(I would like to hide boost behind an alias in case this particular library gets adopted into the standard sometime in the future.)
Is there any way this can be made to work?
#include <boost/range/iterator_range.hpp>
void Foo()
{
}
template< typename T >
void Bar()
{ }
template< typename T >
void Bar(char c)
{ }
void (&FooAlias)() = Foo; // ok
void (&BarAlias)() = Bar<int>; // ok
// boost::iterator_range<const size_t*> (&MakeIterRangeAlias)(const size_t*,const size_t*) =
// boost::make_iterator_range<const size_t*>; // not ok
int main(int argc, char** argv)
{
const size_t v[] = { 3, 5, 1, 5, 29, 15 };
boost::iterator_range<const size_t*> r
= boost::make_iterator_range( std::begin( v ), std::end( v )); // want to alias this
return 0;
}
The error message is:
In file included from /usr/include/boost/iterator/iterator_categories.hpp:15:0,
from /usr/include/boost/iterator/detail/facade_iterator_category.hpp:7,
from /usr/include/boost/iterator/iterator_facade.hpp:14,
from /usr/include/boost/range/iterator_range_core.hpp:23,
from /usr/include/boost/range/iterator_range.hpp:13,
from sandbox.cpp:2:
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int* const> >’:
/usr/include/boost/range/iterator.hpp:63:63: instantiated from ‘boost::range_iterator<const long unsigned int* const>’
sandbox.cpp:20:10: instantiated from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int* const> >::f_ {aka struct boost::range_const_iterator<const long unsigned int*>}’
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int*> >’:
/usr/include/boost/range/iterator.hpp:63:63: instantiated from ‘boost::range_iterator<const long unsigned int*>’
sandbox.cpp:20:10: instantiated from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int*> >::f_ {aka struct boost::range_mutable_iterator<const long unsigned int*>}’
sandbox.cpp:20:10: error: invalid initialization of non-const reference of type ‘void (&)(const size_t*, const size_t*) {aka void (&)(const long unsigned int*, const long unsigned int*)}’ from an rvalue of type ‘<unresolved overloaded function type>’
make: *** [sandbox] Error 1
Using function pointers is a suboptimal way alias a function. It is not as flexible as the original (it can no longer be a template) and you now need to know the exact signature of the function, which may or may not be stable.
Instead try this approach.
template< typename ... Args >
auto MakeIterRangeAlias( Args&& ... args ) -> decltype( /* copy return line here */ )
{
return boost::make_iterator_range( std::forward<Args>(args)... );
}
With almost no work on your part the alias supports the exact signature of the original. Even if it dramatically changes, you're still set. Further, unlike the function pointer approach the optimizer will be able to trivially inline MakeIterRangeAlias so that there is no runtime overhead.