Boost's program_options library now supports boost::optional, can the same be done with std::optional?
I attempted to modify both the documentation example and the code in the PR, but neither seems to work.
For example, the very simple case for integers (before trying template specializations):
void validate(boost::any& v, const std::vector<std::string>& values, std::optional<int>* target_type,
int) {
using namespace boost::program_options;
validators::check_first_occurrence(v);
const string& s = validators::get_single_string(values);
int n = lexical_cast<int>(s);
v = any(std::make_optional<int>(n));
}
fails with the error that the target type is not istreamable:
external/boost/boost/lexical_cast/detail/converter_lexical.hpp:243:13:
error: static_assert failed due to requirement
'has_right_shift<std::__1::basic_istream<char>, std::__1::optional<int>, boost::binary_op_detail::dont_care>::value || boost::has_right_shift<std::__1::basic_istream<wchar_t>, std::__1::optional<int>, boost::binary_op_detail::dont_care>::value'
"Target type is neither std::istream`able nor std::wistream`able"
The problem with things like validate (and operator>> as well) is often ADL¹.
You need to declare the overload in one of the associated namespaces. In this case, because int is a primitive type, the only associated namespaces come from library code:
std for optional, vector, string, allocator, char_traits (yes these all count!)
boost for any
You'd prefer not to add your code in those namespaces, because you might interfere with library functions or invite future breakage when the library implementation details change.
If you had to choose, you'd prefer to choose boost here, because
that's the library providing the feature at hand
the validate free function is explicitly designed to be an customization point
Sidenote: Keep an eye out for tag_invoke - a better way to build customization points in libraries
The Fix
After all this verbiage, the solution is very simple:
namespace boost {
void validate(boost::any& v, const std::vector<std::string>& values,
std::optional<int>*, int) {
using namespace boost::program_options;
validators::check_first_occurrence(v);
const std::string& s = validators::get_single_string(values);
int n = boost::lexical_cast<int>(s);
v = boost::any(std::make_optional<int>(n));
}
} // namespace boost
Adding two lines made it work: Live On Wandbox.
Other Notes:
The "solution" injecting operator>> in general is less pure
because
it has a potential to "infect" all other code with ADL-visible overloads that might interfere. Way more code uses operator>> than
boost's validate function
it thereby invites UB due to
ODR violations,
when another translation unit, potentially legitimely, defines
another operator>> for the same arguments.
On recent compilers you can say vm.contains instead of the slightly abusive vm.count
There's another snag with non-streamable types, where, if you define a default value, you probably also need to specify the string representation with it.
Listing
Compiling on Compiler Explorer
#include <boost/program_options.hpp>
#include <optional>
#include <iostream>
namespace po = boost::program_options;
namespace boost {
void validate(boost::any& v, const std::vector<std::string>& values,
std::optional<int>*, int) {
using namespace boost::program_options;
validators::check_first_occurrence(v);
const std::string& s = validators::get_single_string(values);
int n = boost::lexical_cast<int>(s);
v = boost::any(std::make_optional<int>(n));
}
} // namespace boost
int main(int ac, char* av[]) {
try {
using Value = std::optional<int>;
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("value", po::value<Value>()->default_value(10, "10"),
"value")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
if (vm.contains("value")) {
std::cout << "value is " << vm["value"].as<Value>().value() << "\n";
}
} catch (std::exception& e) {
std::cout << e.what() << "\n";
return 1;
}
}
BONUS
As an added exercise, let's demonstrate that if your optional value_type is not a primitive, but rather your library type, declared in a namespace MyLib, then we don't have most of the trade-offs above:
namespace MyLib {
template <typename T> struct MyValue {
MyValue(T v = {}) : value(std::move(v)) {}
private:
T value;
friend std::istream& operator>>(std::istream& is, MyValue& mv) {
return is >> mv.value;
}
friend std::ostream& operator<<(std::ostream& os, MyValue const& mv) {
return os << mv.value;
}
};
Now you could provide generic validators for any types in your MyLib namespace, be it optional or not, and have ADL find them through your MyLib namespace:
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, T*, int) {
po::validators::check_first_occurrence(v);
v = boost::lexical_cast<T>(
po::validators::get_single_string(values));
}
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, std::optional<T>*, int) {
po::validators::check_first_occurrence(v);
v = std::make_optional(
boost::lexical_cast<T>(
po::validators::get_single_string(values)));
}
} // namespace MyLib
See Live Demo
#include <boost/program_options.hpp>
#include <iostream>
#include <iomanip>
namespace po = boost::program_options;
namespace MyLib {
template <typename T> struct MyValue {
MyValue(T v = {}) : value(std::move(v)) {}
private:
T value;
friend std::istream& operator>>(std::istream& is, MyValue& mv) {
return is >> std::boolalpha >> mv.value;
}
friend std::ostream& operator<<(std::ostream& os, MyValue const& mv) {
return os << std::boolalpha << mv.value;
}
};
// Provide generic validators for any types in your MyLib namespace, be it
// optional or not
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, T*, int) {
po::validators::check_first_occurrence(v);
v = boost::lexical_cast<T>(
po::validators::get_single_string(values));
}
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, std::optional<T>*, int) {
po::validators::check_first_occurrence(v);
v = std::make_optional(
boost::lexical_cast<T>(
po::validators::get_single_string(values)));
}
} // namespace MyLib
int main(int ac, char* av[]) {
try {
using Int = MyLib::MyValue<int>;
using OptInt = std::optional<MyLib::MyValue<int>>;
using OptStr = std::optional<MyLib::MyValue<std::string> >;
po::options_description desc("Allowed options");
desc.add_options()
("ival", po::value<Int>()->default_value(Int{10}),
"integer value")
("opti", po::value<OptInt>()->default_value(OptInt{}, "(nullopt)"),
"optional integer value")
("sval", po::value<OptStr>()->default_value(OptStr{"secret"}, "'secret'"),
"optional string value")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
std::cout << "Options: " << desc << "\n";
if (vm.contains("ival")) {
std::cout << "ival is " << vm["ival"].as<Int>() << "\n";
}
if (vm.contains("opti")) {
if (auto& v = vm["opti"].as<OptInt>())
std::cout << "opti is " << v.value() << "\n";
else
std::cout << "opti is nullopt\n";
}
if (vm.contains("sval")) {
if (auto& v = vm["sval"].as<OptStr>())
std::cout << "sval is " << v.value() << "\n";
else
std::cout << "sval is nullopt\n";
}
} catch (std::exception& e) {
std::cout << e.what() << "\n";
return 1;
}
}
For ./a.out --ival=42 --sval=LtUaE prints:
Options: Allowed options:
--ival arg (=10) integer value
--opti arg (=(nullopt)) optional integer value
--sval arg (='secret') optional string value
ival is 42
opti is nullopt
sval is LtUaE
¹ see also See also Why Does Boost Use a Global Function Override to Implement Custom Validators in "Program Options"
Related
A parser application where I’m working on calls for recursive rules. Besides looking into the Recursive AST tutorial examples of Boost Spirit X3 which can be found here:
https://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/index.html, I was looking for a solution with a std::variant of some types as well as a std::vector of that same
variant type.
In the StackOverflow post titled: Recursive rule in Spirit.X3, I found the code from the answer from sehe a decent starting point for my parser.
I have repeated the code here but I have limited the input strings to be tested. Because the full list from the original is not relevant for this question here.
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>>
{
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
friend std::ostream& operator<<(std::ostream& os, base_type const& v) {
struct {
std::ostream& operator()(float const& f) const { return _os << "float:" << f; }
std::ostream& operator()(int const& i) const { return _os << "int:" << i; }
std::ostream& operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) _os << el << ",";
return _os << ']';
}
std::ostream& _os;
} vis { os };
return std::visit(vis, v);
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
std::cout << "Parsed '" << val << "'\n";
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}
However I would like to use a traditional visitor class rather than making ostream a friend in the variant class. You know just a struct/class with a bunch of function objects for each type you encounter in the variant and a "for loop" for the vector that calls std::visit for each
element.
My goal for the traditional visitor class is to be able to maintain a state machine during printing.
My own attempts to write this visitor class did fail because I ran into an issue with my GCC 8.1 compiler. With GCC during compilation std::variant happens to be std::variant_size somehow and I got the following error:
error: incomplete type 'std::variant_size' used in nested name specifier
More about this here:
Using std::visit on a class inheriting from std::variant - libstdc++ vs libc++
Is it possible giving this constraint on GCC to write a visitor class for the code example I included, so that the ostream stuff can be removed?
Is it possible giving this constraint on GCC to write a visitor class for the code example I included, so that the ostream stuff can be removed?
Sure. Basically, I see three approaches:
1. Add the template machinery
You can specialize the implementation details accidentally required by GCC:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
};
namespace std {
template <> struct variant_size<value> :
std::variant_size<value::base_type> {};
template <size_t I> struct variant_alternative<I, value> :
std::variant_alternative<I, value::base_type> {};
}
See it live on Wandbox (GCC 8.1)
2. Don't (again live)
Extending the std namespace is fraught (though I think it's legal for
user-defined types). So, you can employ my favorite pattern and hide th
estd::visit dispatch in the function object itself:
template <typename... El>
void operator()(std::variant<El...> const& v) const { std::visit(*this, v); }
Now you can simply call the functor and it will automatically dispatch
on your own variant-derived type because that operator() overload does
NOT have the problems that GCC stdlib has:
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
3. Make things explicit
I like this the least, but it does have merit: there's no magic and no
tricks:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
// ...
Again, live
SUMMARY
After thinking a bit more, I'd recommend the last approach, due to the relative simplicity. Clever is often a code-smell :)
Full listing for future visitors:
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
std::ostream& _os;
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
void operator()(float const& f) const { _os << "float:" << f; }
void operator()(int const& i) const { _os << "int:" << i; }
void operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) {
operator()(el);
_os << ",";
}
_os << ']';
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}
I've got a function like this:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
// data loading stuff
callback(body, subject, header);
}
The problem is I'm not necessarily need to use subject and header in my callback function. Now I'm handling it this way:
loadData([](std::string body, std::string, std::string){
std::cout << body;
})
I want to replace it with
loadData([](std::string body){
std::cout << body;
})
and automatically pass to callback function as many arguments as it able to accept.
I don't want to manually overload loadData function for all 3 possible argument counts. I also don't want to use any more complicated lambda syntax on the calling site because my library should be clear for others to use.
Is this possible using C++ STL and Boost?
What about ignoring the following arguments using ... ?
loadData([](std::string body, ...){
std::cout << body;
})
As pointed by StoryTeller (thanks!) the use of ellipsis can be unsupported for non trivial types (see [expr.call]p9 for more details).
To avoid this problem, if you can use C++14, you can use auto ... (better auto && ... to avoid unnecessary copies; thanks Yakk).
loadData([](std::string body, auto && ...){
std::cout << body;
})
I got inspired by one of the other answers, which proposes to make a wrapper that passes the correct number of parameters to the functor. I find this solution very nice, and thought I would try make a general templated wrapper, where the number of arguments is not hardcoded. Here is what I came up with:
#include <string>
#include <functional>
#include <iostream>
struct WrapperHelp
{
template
< typename L
, typename Tuple
, std::size_t... Is
, typename... Ts
>
static auto apply(L&& l, Tuple t, std::index_sequence<Is...>, Ts&&... ts)
-> decltype(l(std::get<Is>(t)...))
{
return l(std::get<Is>(t)...);
}
template
< typename L
, typename Tuple
, std::size_t... Is
, typename T1
, typename... Ts
>
static auto apply(L&& l, Tuple t, std::index_sequence<Is...>, T1&& t1, Ts&&... ts)
-> decltype(WrapperHelp::apply(std::forward<L>(l), std::forward_as_tuple(std::get<Is>(t)..., t1), std::make_index_sequence<sizeof...(Is) +1 >(), ts...))
{
return WrapperHelp::apply(std::forward<L>(l), std::forward_as_tuple(std::get<Is>(t)..., t1), std::make_index_sequence<sizeof...(Is) + 1>(), ts...);
}
};
template<typename L>
struct OptionalWrapper {
public:
OptionalWrapper(L l) : lambda{std::move(l)} {}
template<typename... Ts>
void operator()(Ts&&... ts) const
{
WrapperHelp::apply(lambda, std::tuple<>(), std::index_sequence<>(), std::forward<Ts>(ts)...);
}
private:
L lambda;
};
template<typename L>
auto makeOptionalWrapper(L l) { return OptionalWrapper<L>{std::move(l)}; }
template<class F>
void loadData(OptionalWrapper<F>&& callback)
{
std::string body = "body";
std::string subject = "subject";
std::string header = "header";
double lol = 2.0;
callback(body, subject, header, lol);
}
template<typename L>
void loadData(L callback)
{
loadData(makeOptionalWrapper(std::move(callback)));
}
int main() {
//apply(std::tuple<double>(2), std::tuple<double>(2));
loadData([](auto&& body) {
std::cout << body << std::endl;
});
loadData([](auto&& body, auto&& subject) {
std::cout << body << " " << subject << std::endl;
});
loadData([](auto&& body, auto&& subject, auto&& header) {
std::cout << body << " " << subject << " " << header << std::endl;
});
loadData([](auto&& body, auto&& subject, auto&& header, auto&& lol) {
std::cout << body << " " << subject << " " << header << " " << lol << std::endl;
});
return 0;
}
This should work for any function, with any number of "optional" parameters, and with any types of parameters. It is not the prettiest code, but I hope the idea is clear and can be of some use :)
Live example
You could make a wrapper around the lambda.
template<typename L>
struct OptionalWrapper {
OptionalWrapper(L l) : lambda{std::move(l)} {}
void operator()(std::string body, std::string subject, std::string header) const {
call(lambda, body, subject, header);
}
private:
template<typename T>
auto call(T& l, std::string body, std::string subject, std::string header) const
-> decltype(l(body, subject, header))
{
return l(body, subject, header);
}
template<typename T>
auto call(T& l, std::string body, std::string subject, std::string) const
-> decltype(l(body, subject))
{
return l(body, subject);
}
template<typename T>
auto call(T& l, std::string body, std::string, std::string) const
-> decltype(l(body))
{
return l(body);
}
L lambda;
};
template<typename L>
auto makeOptionalWrapper(L l) { return OptionalWrapper<L>{std::move(l)}; }
Then, use your wrapper like that:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
callback(body, subject, header);
}
template<typename L>
void loadData(L callback)
{
loadData({makeOptionalWrapper(std::move(callback))});
}
I need to convert a tuple to a byte array. This is the code I use to convert to byte array:
template< typename T > std::array< byte, sizeof(T) > get_bytes( const T& multiKeys )
{
std::array< byte, sizeof(T) > byteArr ;
const byte* start = reinterpret_cast< const byte* >(std::addressof(multiKeys) ) ;
const byte* end = start + sizeof(T);
std::copy(start, end, std::begin(byteArr));
return byteArr;
}
Here is how I call it:
void foo(T... keyTypes){
keys = std::tuple<T... >(keyTypes...);
const auto bytes = get_bytes(keys);
}
I need to augment this code such that when a pointer is a part of the tuple, I dereference it to it's value and then pass the new tuple, without any pointers, to the get_bytes() function. How do I detect the presence of a pointer in the tuple? I can then iterate through the tuple and dereference it with:
std::cout << *std::get<2>(keys) << std::endl;
Add a trivial overload: T get_bytes(T const* t) { return getBytes(*t); }.
That would be easy with C++14 :
#include <iostream>
#include <tuple>
#include <utility>
template <class T> decltype(auto) get_dereferenced_value(T &&value) {
return std::forward<T>(value);
}
template <class T> decltype(auto) get_dereferenced_value(T *value) {
return *value;
}
template <class Tuple, class Indexes> struct get_dereferenced_tuple_impl;
template <class... Args, size_t... Index>
struct get_dereferenced_tuple_impl<std::tuple<Args...>,
std::integer_sequence<size_t, Index...>> {
decltype(auto) operator()(std::tuple<Args...> const &originalTuple) {
return std::make_tuple(
get_dereferenced_value(std::get<Index>(originalTuple))...);
}
};
template <class Tuple>
decltype(auto) get_dereferenced_tuple(Tuple const &tupleValue) {
return get_dereferenced_tuple_impl<
Tuple,
std::make_integer_sequence<size_t, std::tuple_size<Tuple>::value>>{}(
tupleValue);
}
int main() {
char c = 'i';
std::tuple<char, char *> t{'h', &c};
auto t2 = get_dereferenced_tuple(t);
std::cout << std::get<0>(t2) << std::get<1>(t2) << "\n";
return 0;
}
If you cannot use C++14, then you would have to write more verbose decltype expressions, as well as include an implementation of std::(make_)integer_sequence.
This has a drawback though : copies will be made before copying the bytes. A tuple of references is not a good idea. The most performant version would be a get_bytes able to serialize the entire mixed tuple directly.
So I was Playing around with c++11 Varidiacs, and I wanted to create a thing called CallClass, basically a class that warps a function, for later call,when all variables are set(truly I have No Idea If It can Be Useful):
#include <tuple>
template <typename OBJ,typename F,typename... VARGS>
class CallClass
{
public:
CallClass(OBJ& object,F callFunction)
:_object(&object),_func(callFunction)
{ }
CallClass(const CallClass& other)
:_func_args(other._func_args)
,_object(other._object)
,_func(other._func)
{ }
template <size_t INDEX>
auto get(){ return std::get<INDEX>(_func_args); }
template <size_t INDEX,typename T>
void set(const T& val){ std::get<INDEX>(_func_args) = val; }
template <size_t INDEX,typename T>
void set(T&& val){ std::get<INDEX>(_func_args) = val; }
auto Call()
{
//throws segmentation Fault Here
return InnerCall<0>(_func_args);
}
virtual ~CallClass() {}
protected:
private:
std::tuple<VARGS...> _func_args;
OBJ* _object;
F _func;
template <size_t INDEX,typename... ARGS>
auto InnerCall(std::tuple<VARGS...>& tup,ARGS... args)
{
auto arg = std::get<INDEX>(tup);
return InnerCall<INDEX + 1>(tup,args...,arg);
}
template <size_t INDEX,VARGS...>
auto InnerCall(std::tuple<VARGS...>& tup,VARGS... args)
{
return (_object->*_func)(args...);
}
};
Now when I try to compile(compiling using IDE:code::blocks, configured to use MINGW On windows ), it prints Compiler:Segmentation Fault, anybody any Ideas?
Usage:
class obj{
public:
obj(int a)
:_a(a)
{ }
virtual ~obj() {}
int add(int b,int c){
return _a + b + c;
}
private:
int _a;
};
int main(){
obj ob(6);
CallClass<obj,decltype(obj::add),int,int> callAdd(ob,obj::add);
callAdd.set<0,int>(5);
callAdd.set<1,int>(7);
cout << "result is " << callAdd.Call() << endl;
return 0;
}
After a Bit of a search i stumbled upon a similar issue, in a way.
apparently the way I'm unpacking the tuple is an issue, so i decided to use a different approach as shown in: enter link description here
had to add a few changes to suit my needs:
changes:
namespace detail
{
template <typename OBJ,typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static auto call(OBJ& obj,F f, Tuple && t)
{
return call_impl<OBJ,F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(obj,f, std::forward<Tuple>(t));
}
};
template <typename OBJ,typename F, typename Tuple, int Total, int... N>
struct call_impl<OBJ,F, Tuple, true, Total, N...>
{
static auto call(OBJ& obj,F f, Tuple && t)
{
return (obj.*f)(std::get<N>(std::forward<Tuple>(t))...);
}
};
}
// user invokes this
template <typename OBJ,typename F, typename Tuple>
auto call(OBJ& obj,F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
return detail::call_impl<OBJ,F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(obj,f, std::forward<Tuple>(t));
}
and changed Call():
auto Call()
{
std::tuple<VARGS...> func_args = _func_args;
return call(*_object,_func, std::move(func_args));
}
I will probably make a few more changes, like passing the tuple as a reference, and making the structs a part of my class.
I'm not sure of the title, because I'm not sure the issue comes from the "copyablility" of my container.
I tryied quite everything but I can't get rid of this error.
Here is a simplified version of my code (please do not challenge the class design, I really would like to keep the end-used syntax in the BOOST_FOREACH):
template <typename T>
class MyContainer
{
public:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::const_iterator const_iterator;
MyContainer(std::vector<T>& vec, boost::mutex& mutex) :
m_vector(vec),
m_lock(mutex)
{
}
iterator begin() { return m_vector.begin(); }
const_iterator begin() const { return m_vector.begin(); }
iterator end() { return m_vector.end(); }
const_iterator end() const { return m_vector.end(); }
private:
std::vector<T>& m_vector;
boost::lock_guard<boost::mutex> m_lock;
};
template <typename T>
struct GetContainer
{
GetContainer(std::vector<T>& vec, boost::mutex& mutex) :
m_vector(vec),
m_mutex(mutex)
{
}
MyContainer<T> Get()
{
return MyContainer<T>(m_vector, m_mutex);
}
std::vector<T>& m_vector;
boost::mutex& m_mutex;
};
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
boost::mutex m;
GetContainer<int> getter(v, m);
BOOST_FOREACH(int i, getter.Get())
{
std::cout << i << std::endl;
}
return 0;
}
The compiler complains about not having a copy constructor for MyContainer::MyContainer(const MyContainer&).
I also have :
error: no matching function for call to ‘MyContainer::MyContainer(boost::foreach_detail_::rvalue_probe >::value_type)’
I follow the extensibility tips:
http://www.boost.org/doc/libs/1_58_0/doc/html/foreach/extensibility.html#foreach.extensibility.making__literal_boost_foreach__literal__work_with_non_copyable_sequence_types
But, making
MyContainer<T> : private boost::noncopyable
doesn't solve the issue.
Nor defining the function
boost_foreach_is_noncopyable
or specializing the template struct
is_noncopyable
for MyContainer (in fact, how would I specialize this template for a template type ?)
Last "tip":
If I remove the mutex and the lock from everywhere (I just pass the vector to GetContainer and to MyContainer), it works.
But it doesn't work if I make
MyContainer<T> : private boost::noncopyable
(I expected it should, so I'm not sure my problem is with BOOST_FOREACH, but maybe because I return a copy of MyContainer with my getter ?)
I thank you if you read me until here, and thanks in advance for help.
Seems to be a limitation of BOOST_FOREACH with move-only types. I didn't find a way around it¹ (except for the - ugly - obvious approach to put the lock_guard in a shared_ptr).
You didn't specify a c++03 requirement, though, so you can make it work without BOOST_FOREACH by replacing lock_guard with unique_lock.
Here's my take on things in c++11 (note how generic it is):
Live On Coliru
#include <boost/thread.hpp>
#include <boost/range.hpp>
namespace detail {
template <typename R, typename M>
struct RangeLock {
RangeLock(R&r, M& m) : _r(r), _l(m) {}
RangeLock(RangeLock&&) = default;
using iterator = typename boost::range_iterator<R>::type;
iterator begin() { using std::begin; return begin(_r); }
iterator end () { using std::end; return end (_r); }
using const_iterator = typename boost::range_iterator<R const>::type;
const_iterator begin() const { using std::begin; return begin(_r); }
const_iterator end () const { using std::end; return end (_r); }
private:
R& _r;
boost::unique_lock<M> _l;
};
}
template <typename R, typename M>
detail::RangeLock<R,M> make_range_lock(R& r, M& mx) { return {r,mx}; }
template <typename R, typename M>
detail::RangeLock<R const,M> make_range_lock(R const& r, M& mx) { return {r,mx}; }
#include <vector>
#include <map>
int main() {
boost::mutex mx;
std::vector<int> const vec { 1, 2 };
std::map<int, std::string> const map { { 1, "one" }, { 2, "two" } };
for(int i : make_range_lock(vec, mx))
std::cout << i << std::endl;
for(auto& p : make_range_lock(map, mx))
std::cout << p.second << std::endl;
for(auto& p : make_range_lock(boost::make_iterator_range(map.equal_range(1)), mx))
std::cout << p.second << std::endl;
}
Prints
1
2
one
two
one
¹ not even using all the approaches from Using BOOST_FOREACH with a constant intrusive list
I post my answer if it can help...
With C++03, I finally provide a copy constructor to be able to use the class with BOOST_FOREACH.
So the issue is moved to another topic: make the class copied in a logic and suitable way.
In my case, I "share the lock and the vector", the user shouldn't use this copy itself if he doesn't want to do bugs, but in BOOST_FOREACH it's okay:
I change the mutex to a recursive_mutex
I change the lock to an unique_lock
and:
MyContainer(const MyContainer& other) :
m_vector(other.vec),
m_lock(*other.m_lock.mutex())
{
}
With C++11
Thanks to Chris Glover on the boost mailling list, a C++11 solution:
You can't do what you are trying to do in C++03. To accomplish it, you
need C++11 move semantics to be able to move the MyContainer out of the Get
function. Even without using BOOST_FOREACH, the following code fails;
GetContainer<int> getter(v, m);
MyContainer<int> c = getter.Get(); // <-- Error.
Here's an example with the necessary changes; I changed the scoped_lock to
a unique_lock and added a move constructor.
template <typename T>
class MyContainer
{
public:
[...]
MyContainer(MyContainer&& other)
: m_vector(other.m_vector)
{
m_lock = std::move(other.m_lock);
other.m_vector = nullptr;
}