Making boost::spirit::hold_any accept vectors - c++

According to its author #hkaiser, here boost::spirit::hold_any is a more performant alternative to boost::any and can, for the most part, be used as a drop-in replacement for the latter. I'm interested in it since it purports to allow for easy output streaming, a feature that boost::any lacks.
While I'm able to input simple types like int into hold_any, I can't seem to get it to hold a container such as std::vector<int> for example. Here'e the code
#include <iostream>
#include <boost/spirit/home/support/detail/hold_any.hpp> // v1.79
#include <vector>
using any = boost::spirit::hold_any;
int main() {
int a1 = 1;
any v1(a1); // OK
std::cout << v1 << std::endl; // OK
std::vector<int> w2 = {5,6};
any v2(w2); // compilation error - invalid operands to binary expression ('std::basic_istream<char>' and 'std::vector<int>')
std::cout << v2 << std::endl;
}
which fails to compile with
hold_any.hpp:155:23: error: invalid operands to binary expression ('std::basic_istream<char>' and 'std::vector<int>')
i >> *static_cast<T*>(*obj);
Presumably, the std::vector<int> needs to be made istream streamable though I'm not sure how to proceed. How does one make this work?

Firstly, that advice is 12 years old. Since then std::any was even standardized. I would not assume that hold_any is still the better choice (on the contrary).
Also, note that the answer you implied contains the exact explanation:
This class has two differences if compared to boost::any:
it utilizes the small object optimization idiom and a couple of other optimization tricks, making spirit::hold_any smaller and faster than boost::any
it has the streaming operators (operator<<() and operator>>()) defined, allowing to input and output a spirit::hold_any seemlessly.
(emphasis mine)
Incidentally, the whole question was about streaming any in the first place, so the answer was on-point there.
The code further drives home the assumption:
// these functions have been added in the assumption that the embedded
// type has a corresponding operator defined, which is completely safe
// because spirit::hold_any is used only in contexts where these operators
// do exist
template <typename Char_>
friend inline std::basic_istream<Char_>&
operator>> (std::basic_istream<Char_>& i, basic_hold_any<Char_>& obj)
{
return obj.table->stream_in(i, &obj.object);
}
template <typename Char_>
friend inline std::basic_ostream<Char_>&
operator<< (std::basic_ostream<Char_>& o, basic_hold_any<Char_> const& obj)
{
return obj.table->stream_out(o, &obj.object);
}
So, indeed that explains the requirement. It's a bit unfortunate that the implementation is not SFINAE-ed so that you'd only run into the limitation if you used the stream_in/stream_out operations, but here we are.

I was able to make the above code work by making a generic vector std::vector<T> both output and input streamable.
#include <iostream>
#include <boost/spirit/home/support/detail/hold_any.hpp>
#include <vector>
using any = boost::spirit::hold_any;
namespace std {
// input stream
template<typename T>
std::istream& operator >> ( std::istream& ins, std::vector<T>& p ) {
size_t sz;
ins >> sz;
for ( size_t i = 0; i < sz; ++i ) {
T tmp;
ins >> tmp;
p.push_back( tmp );
}
return ins;
}
// output stream
template<typename T>
std::ostream& operator << ( std::ostream& outs, const std::vector<T>& p ) {
outs << "[";
for ( size_t i = 0; i < p.size(); ++i ) {
outs << p[i];
if ( i != p.size() - 1 )
outs << " ";
else
outs << "]";
}
return outs;
}
}
I'd appreciate any comments on how to make the above more performant. boost::iostreams perhaps?

Related

Generic comparison operator for structs

In many of my unit tests I need to compare the contents of simple structs having only data members:
struct Object {
int start;
int stop;
std::string message;
}
Now, if I want to write something like:
CHECK(object1==object2);
I always have to implement:
bool operator==(const Object& lhs, const Object& rhs) {
return lhs.start==rhs.start && lhs.stop==rhs.stop && lhs.message=rhs.message;
}
Writing all these comparison functions becomes tedious, but is also prone to errors. Just imagine, what will happen if I add a new data member to Object, but the comparison operator will not be updated.
Then I remembered my knowledge in Haskell and the magic deriving(Eq) directive, which just generates a sane comparison function for free.
How, could I derive something similar in C++?
Happily, I figured out that C++17 comes with a generic operator== and that every struct should be easily convertible to an std::tuple by the virtue of std::make_tuple.
So I boldly tried the following:
#include <tuple>
#include <iostream>
#include <tuple>
template<typename T>
bool operator==(const T& lhs, const T& rhs)
{
auto leftTuple = std::make_tuple(lhs);
auto rightTuple = std::make_tuple(rhs);
return leftTuple==rightTuple;
}
struct Object
{
std::string s;
int i;
double d;
};
int main(int arg, char** args)
{
std::cout << (Object{ "H",1,2. } == Object{ "H",1,2. }) << std::endl;
std::cout << (Object{ "A",2,3. } == Object{ "H",1,2. }) << std::endl;
return EXIT_SUCCESS;
}
But, unfortunately it just doesn't compile and I really don't know why. Clang tells me:
main.cpp:11:18: error: use of overloaded operator '==' is ambiguous (with operand types
'std::tuple<Object>' and 'std::tuple<Object>')
return leftTuple==rightTuple;
Can I possibly fix this compile error to get my desired behavior?
No, since comparing tuples reverts to comparing the elements of the tuple, so leftTuple == rightTuple tries to compare two Objects which is not possible.
that every struct should be easily convertible to an std::tuple by the virtue of std::make_tuple
No, you'll just get a tuple with one element, the struct.
The trick is to use std::tie:
std::tie(lhs.mem1, lhs.mem2) == std::tie(rhs.mem1, rhs.mem2)
but that has the same problem as your original solution. Unfortunately C++17 doesn't have any facility to avoid this problemyou could write a macro :). But in C++20 you will be able to do:
struct Object
{
std::string s;
int i;
double d;
bool operator==(const Object &) const = default;
};
which will generate the correct comparison operators for Object.

Overload operator + for vector: namespace std

I am trying to overload the operator + and += for std::vector, and what I do is
namespace std {
template<class T>
vector<T> operator+(vector<T> x, vector<T> y) {
vector<T> result;
result.reserve(x.size());
for (size_t i = 0; i < x.size(); i++)
result[i] = x[i] + y[i];
return result;
}
}
But I assume this is bad practice, because clang-tidy warns me "Modification of std namespace can result in undefined behavior". Is there other better practice in overloading operator for STL classes?
Best practice is not to do it.
But if you really want to you still can: just don't put it in namespace std.
And don't take your arguments by value, unless you're deliberately doing so in order to make the most of move semantics (which you're not).
I suggest:
Don't overload the operators. Create regular functions instead.
Put the functions in a namespace specific to your app.
Example:
namespace MyApp
{
template <typename T>
std::vector add(std::vector<T> const& lhs, std::vector<T> const& rhs) { ... }
template <typename T>
std::vector& append(std::vector<T>& lhs, std::vector<T> const& rhs) { ... }
}
Inserting functions into std makes your program ill formed, no diagnostic required.
In certain limited circumstances you may insert specializations into std, but that cannot do what you want here.
So you cannot insert vec + vec into std.
Putting an operator in a different namespace is legal, but ill-advised. Operators do not work well when they cannot be found via ADL/Koenig lookup. Code that is seemingly reasonable, like std::accumulate( vec_of_vec.begin(), vec_of_vec.end(), std::vector<int>{} ) fails to compile, among other issues.
The short answer is, vector isn't your type. Don't do this.
You can create helper functions elsewhere, like util::elementwise_add( vec, vec ).
The std did not implement + because both concatination and elementwise operations where reasonable. valarray does implement elementwise operations; possibly what you want is std::valarray<int> instead of std::vector<int>.
Failing all of this, you could write a named operator vec +by_elem+ vec or inherit from std::vector in your own namespace, use that type, and overload + for your type. (Inheriting from std::vector is pretty safe; so long as nobody plays with heap allocated raw pointers to std::vectors or similar)
Whether you implement addition as operator+(...) or as a function add(...), you'd better do it this way:
template<class T>
std::vector<T> operator+(std::vector<T> x, const std::vector<T>& y) {
assert(x.size() == y.size());
for (std::size_t i = 0; i < x.size(); ++i)
x[i] += y[i];
return x;
}
By taking the first vector by value (and not by const-ref) you'll force a compiler to make a copy for you automatically to hold the result.
Addition after reading this comment.
Due to left-to-right associativity of +, an expression like a + b + c is parsed as (a + b) + c. Hence, if the first (and not the second) argument in operator+(... x, ... y) is taken by value, the prvalue returned by a + b can be moved into x. Otherwise, unnecessary copies will be made.
You may should create your own vector class inherits from std::vector and define the new operator
#include <iostream>
#include <vector>
template<class T>
class MyVec : public std::vector<T>
{
public:
MyVec& operator+=(const T& add)
{
reserve(1);
push_back(add);
return *this;
}
};
int main()
{
MyVec<int> vec;
vec += 5;
vec += 10;
for (auto& e : vec)
{
std::cout << e << "\t";
}
std::cin.get();
}
Edit: sry i did not know that this solution causes undefined behaviour. Then i would suggest a similar solution shown in the post above. But why do you need the plus operator? Isnt push_back good enough? You could implement a reference return value to continue the addition. So you can do things like that:
vec + 20 + 30;
to add two elements (20 and 30). This is less code but is is more readable?

Having trouble interpreting this C++ code

Background about code posted: PayRoll is the name of the class. personSalary is a double type variable, and personAge is an integer type variable. The code given is sorting a list by age or by the salary.
struct less_than_salary
{
inline bool operator() (const PayRoll& struct1, const PayRoll& struct2)
{
return (struct1.personSalary < struct2.personSalary);
}
};
struct less_than_age
{
inline bool operator() (const PayRoll& struct1, const PayRoll& struct2)
{
return (struct1.personAge < struct2.personAge);
}
};
I would like some help understanding this section of the given code. I've tried reading what struct is used for and from what I understand, it basically operates as a class and allows you to work with many types of variables at one time. If I'm wrong, what exactly is a struct used for in this context?
Also, I would appreciate it if someone explained what "inline bool operator()" was doing because I've never seen that before and I could not understand by reading the textbook.
Thank you for your help!
Both structs are implementations of a so-called "functor". Given usage like
PayRoll x;
PayRoll y
// initialise x and y
less_than_salary f;
if (f(x,y)) // this calls less_than_salary::operator()(x,y)
std::cout << "X has lower salary than Y\n";
else
std::cout << "X has higher salary than Y\n";
Also, given an array of PayRoll, it is possible to sort
PayRoll a[20];
// initialise elements of a
less_than_salary f;
std::sort(a, a+20, f); // will sort in order of ascending salary
std::sort(a, a+20, less_than_salary()); // does same as preceding two lines
Standard containers (std::vector<PayRoll>, etc) can also be used.
less_than_age allows doing essentially the same thing, but using age rather tnan salary as a sort criterion.
There is no function overloading as such here. Both struct types provide an operator(), but that is not overloading.
A struct like this can be used in the STL function sort, which is avaliable in data structures such as std::list.
#include <list>
#include <iostream>
int main() {
std::list<int> example = {9,8,7,6,5,4,3,2,1};
struct {
bool operator()( const int lhs, const int rhs) {
return lhs < rhs;
}
} compare_list;
example.sort(compare_list);
for(auto &i : example) {
std::cout<<i<<" ";
}
}
Output:
1 2 3 4 5 6 7 8 9
To understand how this works, consider the following:
//..
testS(compare_list);
//..
template <typename T>
void testS(T t) {
std::cout<< t(4,5) << "\n";
std::cout<< t(5,4) << "\n";
}
The output would be
1
0

Printing chars as Integers

I want to control whether my ostream outputting of chars and unsigned char's via << writes them as characters or integers. I can't find such an option in the standard library. For now I have reverted to using multiple overloads on a set of alternative print functions
ostream& show(ostream& os, char s) { return os << static_cast<int>(s); }
ostream& show(ostream& os, unsigned char s) { return os << static_cast<int>(s); }
Is there a better way?
No, there isn't a better way. A better way would take the form of a custom stream manipulator, like std::hex. Then you could turn your integer printing off and on without having to specify it for each number. But custom manipulators operate on the stream itself, and there aren't any format flags to do what you want. I suppose you could write your own stream, but that's way more work than you're doing now.
Honestly, your best bet is to see if your text editor has functions for making static_cast<int> easier to type. I assume you'd otherwise type it a lot or you wouldn't be asking. That way someone who reads your code knows exactly what you mean (i.e., printing a char as an integer) without having to look up the definition of a custom function.
Just an update to an old post. The actual trick is using '+'. Eg:
template <typename T>
void my_super_function(T x)
{
// ...
std::cout << +x << '\n'; // promotes x to a type printable as a number, regardless of type
// ...
}
In C++11 you could do:
template <typename T>
auto promote_to_printable_integer_type(T i) -> decltype(+i)
{
return +i;
}
Credit: How can I print a char as a number? How can I print a char* so the output shows the pointer’s numeric value?
I have a suggestion based on the technique used in how do I print an unsigned char as hex in c++ using ostream?.
template <typename Char>
struct Formatter
{
Char c;
Formatter(Char _c) : c(_c) { }
bool PrintAsNumber() const
{
// implement your condition here
}
};
template <typename Char>
std::ostream& operator<<(std::ostream& o, const Formatter<Char>& _fmt)
{
if (_fmt.PrintAsNumber())
return (o << static_cast<int>(_fmt.c));
else
return (o << _fmt.c);
}
template <typename Char>
Formatter<Char> fmt(Char _c)
{
return Formatter<Char>(_c);
}
void Test()
{
char a = 66;
std::cout << fmt(a) << std::endl;
}
In C++20 you'll be able to use std::format to do this:
unsigned char uc = 42;
std::cout << std::format("{:d}", uc); // format uc as integer 42 (the default)
std::cout << std::format("{:c}", uc); // format uc as char '*' (assuming ASCII)
In the meantime you can use the {fmt} library, std::format is based on.
Disclaimer: I'm the author of {fmt} and C++20 std::format.

c++ combining use of member functions and overloaded operators to filter data passed to stream

I have a complex nested hierachy of objects which I need to filter at output, sucht that only objects which meet certain criteria are written to file.
Suppose I have class A, which comprises an STL vector array of objects B, where each object B comprises an STL vector array of objects C.
Now all the clever stuff has been done and the filtered results need to be written to file:
class A
{
...
std::vector<B> bArray;
std::ostream & filterA(std::ostream &out, int param1,int param2, bool param3)
{
if (param1>0)
{
for (intcurB=0;curB!=bArray.size();curB++)
{
out << bArray.at(curB).filterB(param2,param3);
}
else if (param1<=0) out << "";
return out;
}
};
class B
{
std::vector<C> cArray; std::ostream & filterB(std::ostream &out, int param2, bool param3)
{
if (param2<0)
{
for (int curC=0;curC!=cArray.size();curC++)
{
out << cArray.at(curC);
}
}
else if (param2>0) out << "";
else if(param3) out << "\nInvalid object\n";
else out << "";
return out;
}
};
class C {
bool isSet;
std::vector<int> intArray;
... };
std::ostream & operator <<(std::ostream & out, C &c)
{
if(c.isSet)
{
for (int curInt=0;curInt!=intArray.size();curInt++)
{
out << c.intArray.at(curInt) << " ";
}
out << "\n";
}
else if (!c.isSet) out << "";
return out;
}
int main()
{
A aObject;
....
// Now lets write filtered objects to file
std::ofstream outputFile("/home/user/test.txt");
if (outputFile.is_open())
{
outputFile << aObject.filterA(outputFile,1,-1,false);
outputFile.close();
}
return 0;
}
The code works i.e. it compiles and runs but the address of the ostream object is written to file too!
My questions are
Is the general methodology advisable?
Is there a better solution (possibly using traits)?
Are you looking for a code-review?
There are a few things I would correct there.
Does A have any purpose other than a printing formatter for the array of B? Does B live its own existence. If so, let A hold a const reference to the vector of B rather than copying it.
Similarly B as a collection of C, although here it must be a pointer to the vector not a reference as B must be assignable to be in a vector (unlike with A which is not itself a vector element).
You could use an algorithm to loop or BOOST_FOREACH. In any case your looping construct is not the best. Slightly better to use iterators. If you use indexes then size_t or vector::size_type as the index. Better to calculate size() once outside the loop or in the first part of the for eg
for( std::vector<B>::size_type i = 0, len = v.size(); i != len; ++i )
Do not use at(). You know your indexes are not out of bounds. Prefer operator[] if you have to use this construct.
Neither filterA nor filterB modify their classes so make them const member functions.
Streaming empty strings is just pointless code. It's one thing if you have a string variable that might be empty but os << "" achieves nothing.