I have a boost recursive variant as below. When I compare two recursive variant object using assert, it works fine but with EXPECT_EQ, it gives compile error.
typedef boost::make_recursive_variant<bool, boost::uint8_t, boost::uint32_t,
boost::int32_t, double, std::string, boost::uuids::uuid>::type rvariant_type;
variant_type b1 = true;
rvariant_type b2 = true;
assert(b1 == b2); //work fine
EXPECT_EQ(b1,b2); //gives compiler error.
EXPECT_EQ(boost::get<bool>(b1), boost::get<bool>(b2)); //works fine
boost/v1.46.1/include/boost/variant/detail/variant_io.hpp:64: error: no match for ‘operator<<’ in ‘((const boost::detail::variant::printer > >*)this)->boost::detail::variant::printer > >::out_ << operand’
gtest makes heavy use of streams for output but it seems that the boost::variant support for printing via an overloaded operator<< is very limited, if not nonexistant.
Take a look at this:
#include <boost/variant.hpp>
#include <boost/cstdint.hpp>
#include <boost/uuid/uuid.hpp>
#include <iostream>
typedef boost::make_recursive_variant<bool, boost::uint8_t, boost::uint32_t,
boost::int32_t, double, std::string, boost::uuids::uuid>::type rvariant_type;
int main() {
rvariant_type v1 = true;
std::cout << v1 << std::endl;
return 0;
}
This very short program gives the same compilation error you got from gtest.
Supplementing it with this:
std::ostream& operator<<(std::ostream& out, const rvariant_type& p) {
return out << boost::get<bool>(p);
}
makes my test compile, I'll take a look if I can make your example work as well.
UPDATE: I just compiled and successfully ran a test based on your code after putting the above-mentioned operator<<, so the lack of an operator<< is precisely what was causing it.
Related
Previous question
For reasons unknown to me, my code stopped working today. For preimplemented functions I have a relay code like this
Math_Node& Function_Manager::relay_complex_to_std(Math_Node& arg, std::function<Complex(const Complex&)> f) const{
if( arg.children_.size() != 1 ){
throw std::runtime_error("Function expects exactly one argument.");
}
evaluate(*arg.children_[0]);
if( std::holds_alternative<Complex>(arg.children_[0]->data_) ){
arg.data_ = f(std::get<Complex>(arg.children_[0]->data_));
arg.children_.clear();
}
return arg;
}
with the types
using Decimal = double;
using Complex = std::complex<Decimal>;
This can be called by a different function like
Math_Node& Function_Manager::sqrt(Math_Node& arg) const{
//return relay_complex_to_std(arg, std::sqrt<Complex::value_type>);
return relay_complex_to_std(arg, [](Complex a){return std::sqrt(a);});
}
The commented line stopped working with the error message
In member function ‘Numeric_Calculator::Math_Node& Numeric_Calculator::Function_Manager::sqrt(Numeric_Calculator::Math_Node&) const’:
functionmanager.cpp:214:72: error:
no matching function for call to ‘Numeric_Calculator::Function_Manager::relay_complex_to_std(Numeric_Calculator::Math_Node&, unresolved overloaded function type>) const’
return relay_complex_to_std(arg, std::sqrt<Complex::value_type>);
Why is the function type not resolved? It works when I put it in a lambda.
Compiler:
g++-9 --version
g++-9 (Ubuntu 9.2.1-17ubuntu1~18.04.1) 9.2.1 20191102
edit:
Thanks to Jarod42 for pointing out the overload with valarray. You can see for yourself that de-commenting the below line will result in the same error
#include <cmath>
#include <complex>
#include <functional>
#include <iostream>
//#include <valarray>
using Complex = std::complex<double>;
Complex relay(Complex arg, std::function<Complex(Complex)> f){
return f(arg);
}
int main(){
std::function<Complex(Complex)> f = std::sqrt<Complex::value_type>;
std::cout << std::sqrt(4.0) << "\n";
std::cout << relay(Complex(-2,0), std::sqrt<Complex::value_type>) << "\n";
return 0;
}
std::sqrt<double> might be ambiguous, it might be
std::sqrt(std::complex<double>)
std::sqrt(std::valarray<double>)
std::sqrt(Integral) (not accepting double)
And whereas std::complex one might be converted to the expected std::function, name resolution doesn't take that conversion into account.
See Address of an overloaded function for more details.
This code snippet (https://gcc.godbolt.org/z/hKDMxm):
#include <iostream>
#include <sstream>
using namespace std;
int main() {
auto s = (ostringstream{} << "string").str();
cout << s;
return 0;
}
compiles and runs as expected with msvc, but fails to compile with clang 9.0.0 and gcc 9.2 giving this error message:no member named 'str' in 'std::basic_ostream<char>'. Looking at https://en.cppreference.com/w/cpp/io/basic_ostringstream/str there is clearly str() member of ostringstream. Why clang and gcc are failing to compile this code?
there is clearly str() member of ostringstream
Yes, but according to cppreference this overload of << should return a reference to basic_ostream<...> rather than ostringstream.
libstdc++ (GCC's standard library) does exactly this, while libc++ (Clang's standard library) and MSVC's standard library behave incorrectly here, technically.
However, it seems there is an open defect report suggesting that the overload of << that works with rvalue streams should return the exact stream type that was passed to it. If it gets accepted, your code will be valid.
operator<< is member of std::ostream, and returns std::ostream& as described here
MSVC obviously has own overload this operator for std::ostringstream, what is not in standard
I ran into the same problem, and solved it with a wrapper class like this:
#include <sstream>
struct StreamHelper
{
std::ostringstream stream;
template< typename T >
StreamHelper& operator<<( const T& value )
{
stream << value; return *this;
}
std::string str() const
{
return stream.str();
}
operator std::string() const
{
return stream.str();
}
};
Then you can do your one-liner:
auto s = (StreamHelper() << "string1," << "string2").str();
If the compiler can figure out that the target type is a string, you don't need the .str() at the end and can use the implicit cast operator.
std::string s = (StreamHelper() << "string1," << "string2");
I see two ways of accessing a boost::optional variable:
The dereference operator on the variable
The variable itself
If I have this code snippet:
#include <boost/optional.hpp>
#include <iostream>
int main()
{
boost::optional<int> oi;
std::cout << oi << "\n";
}
(where oi is uninitialized) and compile it using "g++-4.9 /tmp/optional.cc" followed by ./a.out, I get 0,
but with this:
#include <boost/optional.hpp>
#include <iostream>
int main()
{
boost::optional<int> oi;
std::cout << *oi << "\n";
}
I get:
a.out: /usr/include/boost/optional/optional.hpp:631: boost::optional<T>::reference_type boost::optional<T>::get() [with T = int; boost::optional<T>::reference_type = int&]: Assertion `this->is_initialized()' failed.
Aborted (core dumped)
which is the expected behavior.
You must have been using an older version of Boost. Your first case triggered a conversion to bool; since the optional does not contain a value, the result of the conversion is false, which is printed as 0.
Newer versions (1.56-1.57) added an operator<< function template declaration to <boost/optional.hpp>
template<class CharType, class CharTrait, class T>
std::basic_ostream<CharType, CharTrait>&
operator<<(std::basic_ostream<CharType, CharTrait>& out, optional<T> const& v);
to catch this kind of mistakes and cause a linker error instead.
Note that including <boost/optional/optional_io.hpp> allows you to actually use the stream operators with optional, in which case optionals that do not contain a value are printed as --.
boost::optional<T> ostream helpers are actually available since boost 1.34. See http://www.boost.org/doc/libs/1_34_0/boost/optional/optional_io.hpp
Note that one needs to EXPLICITLY include <boost/optional/optional_io.hpp> to enable these helpers. It is NOT included by <boost/optional.hpp>.
I'm trying to find an element in a vector of structs. The code works when searching in a case-sensitive manner. When I try enhancing it to be case-insensitive, I run into two issues.
Simply including boost/algorithm/string.hpp breaks the previously working VS2010 build. The error is "'boost::phoenix::bind' : ambiguous call to overloaded function". Builds OK in Xcode. Any way to disambiguate the bind?
I guess I've got the syntax wrong in the second (commented out) find_if line, adding the istarts_with call. I get errors from the phoenix headers saying "error: no type named 'type'". Assuming issue #1 can be fixed, how should I correct this line?
Thanks!
Code:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <boost/algorithm/string.hpp> // This include breaks VS2010!
#include <boost/phoenix/bind.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/stl/algorithm.hpp>
using namespace boost::phoenix;
using boost::phoenix::arg_names::arg1;
using boost::istarts_with;
using std::string;
using std::cout;
// Some simple struct I'll build a vector out of
struct Person
{
string FirstName;
string LastName;
Person(string const& f, string const& l) : FirstName(f), LastName(l) {}
};
int main()
{
// Vector to search
std::vector<Person> people;
std::vector<Person>::iterator dude;
// Test data
people.push_back(Person("Fred", "Smith"));
// Works!
dude = std::find_if(people.begin(), people.end(), bind(&Person::FirstName, arg1) == "Fred");
// Won't build - how can I do this case-insensitively?
//dude = std::find_if(people.begin(), people.end(), istarts_with(bind(&Person::FirstName, arg1), "Fred"));
if (dude != people.end())
cout << dude->LastName;
else
cout << "Not found";
return 0;
}
You'd need two binds to make it work. First define:
int istw(string a, string b) { return istarts_with(a,b); }
and then use the following as the predicate for the find_if:
bind(&istw,bind(&Person::FirstName, arg1),"fred")
Two comments:
Make sure you're using the right bind, namely, use boost::phoenix::bind.
The definition of istw is probably unnecessary but I could not find the right way to replace it.
Lyrics:
I try to implement a task pool over MPI. So I need some kind of RPC but one that would work between different parts of my program, meaning processor A wants processor B to call function C with argument D. We can not pass pointers to functions between processes like we do with threads, so we need some wrapper container to hold our function pointers at each process instance. All inside one source file\one program... So I started wondering about How to store functional objects with different signature in a container. My API Idea back then was wrong - it is better to define all functions in function pool at that pool construction (at least it shall be much easier to implement). But while implementing I faced next trouble:
Problem:
Such simple code (function_types, mpl::vector, variant):
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <string>
template <class T>
int append(T val)
{
std::cout << "hello";
return 0;
}
int main()
{
boost::variant<boost::function_types::function_type< boost::mpl::vector<int,int> >::type , boost::function_types::function_type< boost::mpl::vector<int,std::string> >::type > a;
return 0;
}
Will not compile falling with:
Error 1 error C2066: cast to function type is illegal c:\program files\boost\include\boost\variant\variant.hpp 1231 1
And looking at source we see:
this code block:
variant()
{
// NOTE TO USER :
// Compile error from here indicates that the first bound
// type is not default-constructible, and so variant cannot
// support its own default-construction.
//
new( storage_.address() ) internal_T0();
indicate_which(0); // zero is the index of the first bounded type
}
So I wonder: How to get around this error?
Also I tried:
#include <boost/function_types/function_type.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <iostream>
#include <string>
template <class T>
int append(T val)
{
std::cout << "hello";
return 1;
}
int main()
{
boost::variant< boost::function<int (std::string) >, boost::function<int (int) > > a;
a= &append<int>;
return 0;
}
Which fails with:
Error 1 error C2668: 'boost::detail::variant::make_initializer_node::apply<BaseIndexPair,Iterator>::initializer_node::initialize' : ambiguous call to overloaded function c:\program files\boost\include\boost\variant\variant.hpp 1330
Any Ideas on how to make boost.variant hold functions?
Of course we can play with shared pointers to functors like so:
#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <string>
template <class in, class out>
struct s_append
{
out operator()(in val) {
std::cout << "hello";
return out();
}
};
int main()
{
boost::variant<boost::shared_ptr<s_append<int, int> >, boost::shared_ptr< s_append<std::string, int> > > a;
boost::shared_ptr<s_append<int, int> > b(new s_append<int, int> );
a=b;
return 0;
}
and it would compile but resulting API sucks - you have to 1) create functors for all functions you want to use (meaning limit there use of current process scope); 2) use shared_pointers and so I don't really even get how to call functions nested that way (simple first guess (*a)(22); just won't compile =( and API starts to be as bad as we would have using Boost.Any).
Try inserting a dummy type as the first argument of the variant. As the comment you found explains, only the first type in the variant is used for the variant's own default constructor. You could use an empty struct type for this (struct NoFunction {};).
That said, you may have been onto something with the idea to use boost::functions as the types in the variant...they are default-constructible at least. I'm not sure what the other error you had from that approach was caused by, but just wanted to let you know you could pursue that angle more if you can't use the dummy-type workaround I mentioned.