C++: problem with inserting custom objects into std:set<SomeObject> [duplicate] - c++

I've had several programs I made in which the compiler didn't flag any errors when I wrote std::set with my own objects but as soon as I attempted to build the program I got some error that seemed to be pointing to some implementation file for std::set. For example, in my program right now the compiler is pointing to the line
struct _LIBCPP_TYPE_VIS_ONLY less : binary_function<_Tp, _Tp, bool>
{
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x < __y;} // <---- That's the problem line
};
with the error
Invalid operands to binary expression ('const XMLNode' and 'const XMLNode')
and that traces back to the line
std::set<XMLNode> children;
in my code. Is my assumption correct that the program is confused because it doesn't know how to compare XMLNode elements? If so, what is a data structure I can use similar to std::set except that it's equipped to hold any type of element? I want something that holds objects of the same type without any repeats and preferably with fast access.

Trees (the underlying structure of a set) rely on being able to compare objects so as to decide in which branch to insert them and, in the end, provide O(log n) accesses.
Therefore, if you want to use std::set, your type needs to provide a way to compare objects - either through operator <, an implementation of std::less<XMLNode>, or by passing your comparer when declaring the set through Compare, its first template argument.
If the concept of comparison does not apply to XMLNode, then you may be interested in either making up an artificial comparison criterion, or using std::unordered_set (which offers amortized O(1) accesses) and providing an implementation for std::hash<XMLNode>.

Related

for_each algorithm to loop over boost::multi_array

Related questions have been asked here before, but I still haven't found a satisfactory answer, so I will try to explain my problem and hope someone can enlighten me.
I am currently writing some code using boost::multi_array, and the code itself is also dimension independent. I need to loop over all elements stored in the multi_array and do something with them. I am looking to do this in a STL-like way:
for_each(begin(array), end(array), function);
Or something similar. Other questions have pointed me to an example on the boost page itself:
for_each example
for_each implementation
Which is more or less exactly what I want. The problem comes when one tries to simply import this code into a larger program. One would naturally like to both wrap the function itself in some namespace, and use for example the C++ functionals as the function object. Doing any of these two will create template lookup problems for the compiler.
Does anyone know either how I can work around the template lookup issue, or an alternative way of doing it (that is hopefully as pretty)?
Additional info:
Compilation error when wrapping the for_each definitions in a namespace
./for_each.hpp:28:3: error: call to function 'for_each' that is neither visible in the template definition nor found by
argument-dependent lookup
for_each(type_dispatch,A.begin(),A.end(),xform);
^
./for_each.hpp:41:5: note: in instantiation of function template specialization
'boost_utilites::for_each<boost::detail::multi_array::sub_array<double, 1>,
double, times_five>' requested here
for_each(type_dispatch,*begin,xform);
^
./for_each.hpp:50:3: note: in instantiation of function template specialization 'boost_utilites::for_each<double,
boost::detail::multi_array::array_iterator<double, double *, mpl_::size_t<2>, boost::detail::multi_array::sub_array<double,
1>,
boost::random_access_traversal_tag>, times_five>' requested here
for_each(boost::type<typename Array::element>(),A.begin(),A.end(),xform);
^
foreach_test.cpp:46:19: note: in instantiation of function template specialization
'boost_utilites::for_each<boost::multi_array<double, 2,
std::allocator<double> >, times_five>' requested here
boost_utilites::for_each(A,times_five());
^
./for_each.hpp:37:6: note: 'for_each' should be declared prior to the call site or in an associated namespace of one of its
arguments
void for_each (const boost::type<Element>& type_dispatch,
^
1 error generated.
When using a std::function object instead of the times_five object in the example, one gets basically the same compilation error.
Compiled with clang version 3.4-1ubuntu3.
Just
std::for_each(array.data(), array.data() + array.num_elements(), function);
To make it work with functions that expect an random-access range (with .begin(), .end() and .size()) use
auto elements = boost::make_iterator_range(array.data(), array.data() + array.num_elements();
// e.g.
for (auto& element : elements) {
...
}
I personally like to use this with generate_n or fill_n etc.:
std::for_each(array.data(), array.num_elements(), 0);
Reference docs
element* data();
const element* data() const;
This returns a pointer to the beginning of the contiguous block that
contains the array's data. If all dimensions of the array are
0-indexed and stored in ascending order, this is equivalent to
origin(). Note that const_multi_array_ref only provides the const
version of this function.
and
size_type a.num_elements()
This returns the number of elements contained in the array. It is equivalent to the following code:
std::accumulate(a.shape(),a.shape+a.num_dimensions(),
size_type(1),std::multiplies<size_type>());>

Why is g++ saying 'no match for ‘operator=’ when there clearly is, and Visual Studio can see that there is?

I'm writing an interface library that allows access to variables within tables (up to a theoretically infinite depth) in an object of type regula::State. I'm accomplishing this by overloading operator[] within a class, which then returns another of that same class, and calls operator[] again as needed. For example:
regula::State t;
t["math"]["pi"] = 3.14159;
The above is supposed to place the value 3.14159 within variable pi in table math. Basically, it does this by have t return a proxy object representing math, which returns another proxy object representing pi, to which we actually save the variable. The internals of this aren't really relevant to the question, but here is the function header.
LObject LObject::operator[] (const std::string name);
Basically, in the example above, the program should call t's operator[] with the string "math" and return another object, and then call that object's operator[] with the string "pi", which returns the final object, and then assigns the value to that one using operator=.
template <typename T>
T LObject::operator= (const T& value);
The T returned is just a copy of the value passed.
Now, my code produces NO errors in Visual C++ 2008 and works perfectly. But when I try to compile it on Linux with g++, I get the following error:
../../test/regula-test.cpp:100: error: no match for ‘operator=’ in
‘L.regula::State::operator[](std::basic_string<char, std::char_traits<char>,
std::allocator<char> >(((const char*)"Numbers"), ((const std::allocator<char>&)((const
std::allocator<char>*)(& std::allocator<char>()))))) = Numbers’
../../include/regula.hpp:855: note: candidates are: regula::LObject&
regula::LObject::operator=(const regula::LObject&)
For some reason, g++ seems to be trying to call operator= on operator[], rather than on the returned object like it is supposed to be.
I can actually fix this error by replacing the return type on operator= with void:
template <typename T>
/*T*/ void LObject::operator= (const T& value);
But this is not preferable, and besides, I have similar errors in several other locations with a similarly overloaded operator==:
../../test/regula-test.cpp:153: error: no match for ‘operator==’ in ‘pi ==
L.regula::State::operator[](std::basic_string<char, std::char_traits<char>,
std::allocator<char> >(((const char*)"pi"), ((const std::allocator<char>&)((const
std::allocator<char>*)(& std::allocator<char>())))))’
I don't understand why this error is occurring in g++, or why it is not occurring in Visual C++. Can anyone shed any light on this or recommend any solutions?
Section 5.17 of the ISO standard says
There are several assignment operators, all of which group right-to-left. All require a modifiable lvalue as their left operand, and the type of an assignment expression is that of its left operand. The result of the assignment operation is the value stored in the left operand after the assignment has taken place; the result is an lvalue.
Your operator= returns not only the wrong type, but not even an lvalue. Assuming GCC's error message didn't include any other candidates besides operator=(const regula::LObject&), GCC has simply ignored your overload entirely. The operator= it mentions is the default, automatically generated function.
On second glance, your operator[] also should return a reference. As written, no assignment expressions like your example should work at all.
So, you should have functions
LObject &LObject::operator[] (const std::string name);
and
template <typename T>
LObject &LObject::operator= (const T& value);

Instantiating an overload of std::less outside of class that is being specialized

I am having a design problem with my code. I want to be able to an std::map with a key value pair of pcl::PointCloud and LidarFile(my own created class), but that requires the < operator to be overloaded since std::map uses comparisons, OR the std::less function template overloaded. The code relating to pcl::PointCloud is in a separate translation unit, and I would rather not modify it, but in order to specify a template specialization for pcl::PointCloud it seems like I have to. So how do I specify the < operator for pcl::PointCloud if it is in a separate translation unit because the error I get now? I am getting both the error
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:63:21: error:
invalid operands to binary expression ('const
pcl::PointCloud<pcl::PointXYZRGB>' and 'const
pcl::PointCloud<pcl::PointXYZRGB>')
{return __x < __y;}
and I assume this is because I need to overload the < operator and also get this error:
/Users/wfehrnstrom/Demeter/Map.cpp:3:21: error: explicit specialization of
'std::__1::less<pcl::PointCloud<pcl::PointXYZRGB> >' after instantiation
template<> struct less<pcl::PointCloud<pcl::PointXYZRGB> >{
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Could anyone guide me on correct design principle in this situation or possibly correct any misguided assumptions I have in this situation? I really appreciate it.

error by move assignment of map with non-copyable (but movable) key

Why does this doesn't work:
#include <memory>
#include <map>
std::map<std::unique_ptr<char>, std::unique_ptr<int>> foo();
std::map<std::unique_ptr<char>, std::unique_ptr<int>> barmap;
int main(){
barmap=foo();
return 0;
}
while this does:
#include <memory>
#include <map>
std::map<std::unique_ptr<char>, std::unique_ptr<int>> foo();
std::map<std::unique_ptr<char>, std::unique_ptr<int>> barmap;
int main(){
std::map<std::unique_ptr<char>, std::unique_ptr<int>> tmp(foo());
using std::swap;
swap(barmap, tmp);
return 0;
}
This has to do with the fact that key type in the map is not copyable (does std::map require that?). Relevant error lines when compiling with g++ -std=c++14:
/usr/include/c++/4.9/ext/new_allocator.h:120:4: error: use of deleted function ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const std::unique_ptr<char>; _T2 = std::unique_ptr<int>]’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^
In file included from /usr/include/c++/4.9/bits/stl_algobase.h:64:0,
from /usr/include/c++/4.9/memory:62,
from pairMove.cpp:1:
/usr/include/c++/4.9/bits/stl_pair.h:128:17: note: ‘constexpr std::pair<_T1, _T2>::pair(std::pair<_T1, _T2>&&) [with _T1 = const std::unique_ptr<char>; _T2 = std::unique_ptr<int>]’ is implicitly deleted because the default definition would be ill-formed:
constexpr pair(pair&&) = default;
^
/usr/include/c++/4.9/bits/stl_pair.h:128:17: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = char; _Dp = std::default_delete<char>]’
In file included from /usr/include/c++/4.9/memory:81:0,
from pairMove.cpp:1:
/usr/include/c++/4.9/bits/unique_ptr.h:356:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
Entire error message to be seen at ideone.
It seems to me that defaulted move constructor of std::pair attempts to use a copy constructor of std::unique_ptr. I presume that map assignment operator uses move assignments of new map contents over the old ones, and std::swap cannot do this since it needs to keep old contents intact, so it just swaps internal data pointers, so it avoids problems.
The necessity to (at least be able to) move assign might come from problems with allocator_traits<M::allocator_type>::propagate_on_container_move_assignment in C++11, but I was under impression that in C++14 the whole thing was fixed. I am not sure why STL would choose to move-assign elements instead of just exchanging data pointers between containers in move-assignment operator.
And all of the above doesn't explain why move-assignment of pairs contained in moved map fails - IMHO it shouldn't.
Btw: g++ -v:
gcc version 4.9.2 (Ubuntu 4.9.2-0ubuntu1~14.04)
I believe this is a bug quality of implementation issue in libstdc++. If we look in the container requirements table (now table 100), one of the requirements is:
a = rv
where a is a value of type X (the container class) and rv denotes a non-const rvalue of type X. The operational semantics are described as:
All existing elements of a are either move assigned to or destroyed
It is stated in [map.overview] that:
A map satisfies all of the requirements of a container
One of those requirements is move assignment. Now apparently libstdc++'s approach is to move assign elements even in the case where Key is non-copyable (which would make pair<const Key, T> non-moveable - note that it's only Key's noncopyability that is relevant here). But there is no mandate that move assignment happens, it is merely an option. Note that the code compiles fine with libc++.
To me this looks like a fundamental failure of the specification in the C++ standard. The specification goes too far in "do not repeat yourself", as to become unreadable and ambiguous (imho).
If you read further to the table Allocator-aware container requirements this same row says (for a = rv):
Requires: If allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is false, T is MoveInsertable into X and MoveAssignable. All existing elements of a are either move assigned to or destroyed. post: a shall be equal to the value that rv had before this assignment.
I think everyone can agree that std::map<std::unique_ptr<char>, std::unique_ptr<int>> is an allocator-aware container. Then the question becomes: What are the requirements on its move assignment operator?
If we look only at the Allocator-aware container requirements, then MoveInsertable and MoveAssignable are only required if allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is false. And this is a weaker requirement than stated by the Container requirements table which states that all elements must be MoveAssignable regardless of the properties of the allocator. So must allocator-aware containers also meet the stricter requirements of containers?
Let's unwind this to what the standard should say if it wasn't trying so hard to not repeat itself.
What does the implementation require?
If allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is true then all ownership of memory resources can be transferred from the rhs to the lhs during move assignment. This means that map move assignment can do nothing but O(1) pointer twiddling to accomplish move assignment (when memory ownership can be transferred). Pointer twiddling does not require any operations on the objects that the pointers point to.
Here is the libc++ implementation of map assignment when allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is true:
https://github.com/llvm-mirror/libcxx/blob/master/include/__tree#L1531-L1551
One can see that absolutely no requirements need to be placed on the key_type or value_type.
Should we artificially place requirements on these types?
What purpose would that serve? Would it help or hurt clients of std::map?
My personal opinion is that making requirements on client types that aren't needed will only serve to frustrate the clients.
I also believe that the current style of specification of the C++ standard is so convoluted that even experts can't agree on what the specification says. This isn't because the experts are idiots. It is because making a correct, unambiguous specification (on this scale) is truly a very difficult problem.
Finally I believe that the intent is (or should be) that the Allocator-aware container requirements supersede the Container requirements when a specification conflict arises.
One final complication: In C++11:
allocator_traits<allocator<T>>::propagate_on_container_move_assignment{} is false_type
where as in C++14:
allocator_traits<allocator<T>>::propagate_on_container_move_assignment{} is true_type
So the libstdc++ behavior is conforming in C++11, and the libc++ behavior is conforming in C++14. LWG issue 2103 made this change.
barmap=foo();
is allowed to require a move-assignment into the map's value_type.
Reasoning:
from §23.4.4.1
For a map<Key,T> the key_type is Key and the value_type is pair<const
Key,T>.
§ 23.2.3
5 For set and multiset the value type is the same as the key type. For map and multimap it is equal to pair<const Key, T>.
7 The associative containers meet all the requirements of Allocator-aware containers (23.2.1), except that
for map and multimap, the requirements placed on value_type in Table 95 apply instead to key_type
and mapped_type. [ Note: For example, in some cases key_type and mapped_type are required to be
CopyAssignable even though the associated value_type, pair, is not
CopyAssignable. — end note ]
From Table 95:
Expression :
a = rv
Return type :
X&
Operational semantics:
All existing elements of a are either move assigned to or destroyed
Assertion/note pre-/post-condition:
a shall be equal to the value that rv had before this assignment
Complexity:
linear
so you would need to provide a const Key&& move-assignment to make it portable.
like this:
#include <memory>
#include <map>
struct key {
key(key&&);
key(const key&&);
key& operator=(key&&);
key& operator=(const key&&);
};
bool operator<(const key& l, const key& r);
struct value {
};
using map_type = std::map<key, value>;
map_type foo();
map_type foo2();
int main(){
auto barmap=foo();
barmap = foo2();
return 0;
}
see it compile here: https://godbolt.org/g/XAQxjt
link to 2015 draft standard I have used (I know there is a later one, but the line remains in the most recent draft, now in table 100)
http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4527.pdf
My apologies to anyone who finds the answer unacceptable, but the words really are there.

Is there an implicit template<typename T>operator<<(const ostream&,T)?

I have a class I've written, meant to represent vectors (in the linear algebra sense). I just started writing it so it isn't finished, but i've pasted it and some test code here
I'm not really sure what's going on. I was going to write an overloaded operator<< for testing in a second, so I went ahead and put it in my main function (so I could use compiler errors to make sure I'd written it properly).
What does this warning mean? why it is looking at the address of v? I tried removing the parentheses from v, and I end up with this, a bunch of horrible template errors:
`
In function 'typename boost::range_const_iterator<C>::type boost::range_detail::boost_range_begin(const C&) [with C = vect<float, 3u>]':
/usr/local/include/boost/range/begin.hpp:164: instantiated from 'typename boost::range_const_iterator<C>::type boost::begin(const T&) [with T = vect<float, 3u>]'
prelude/more_stdlib_ostreaming.hpp:64: instantiated from 'void more_stdlib_ostreaming_detail::print_range(std::basic_ostream<_CharT, _Traits>&, const Range&) [with C = char, Tr = std::char_traits<char>, Range = vect<float, 3u>]'
prelude/more_stdlib_ostreaming.hpp:76: instantiated from 'typename more_stdlib_ostreaming_detail::snd<typename R::iterator, std::basic_ostream<_CharT, _Traits>&>::type operator<<(std::basic_ostream<_CharT, _Traits>&, const R&) [with C = char, Tr = std::char_traits<char>, R = vect3f]'
t.cpp:42: instantiated from here
Line 45: error: 'const class vect<float, 3u>' has no member named 'begin'`
I can sort of see whats going on here, tho. It looks like it is somehow using boost's range for and trying to iterate over my container, and it is failing because I haven't defined begin() and end(). The same thing happens if I instantiate v using v(some_float) rather than without the parens.
So, two questions:
Why is v() behaving differently than v? I thought that declaring a object without parens always calls the default ctor anyway, and explicitly calling the default ctor made no difference?
What is codepad's compiler (gcc 4.1.2) doing here? Does it have a template that automatically tries to generate an appropriate operator<
Also, feel free to tell me anything else I'm doing stupid/wrong/bad style here (besides rolling my own matrix math library for fun, which I know is unnecessary. I'm doing it as an exercise)
First of all, vect3f v(); declares a function (named v), taking no parameters and returning vect3f. And the operator<< that is being called is called for this function pointer (which is implicitly converted to bool, because there's no overload for function pointers).
vect3f v; is the correct way of creating default-constructed object.
And no, compiler won't try to generate ostream& operator<<(ostream& /* ... */) for you. There are however many overloads for all fundamental types and even some other types (such as std::string).
You can check all basic overloads here.

Resources