boost::lexical_cast is a great tool but in my application I ran into a limitation in string -> bool conversion that is bugging me. I need to convert all strings like "0", "false" and "FALSE" into false and "1", "true" and "TRUE" into true.
boost::lexical_cast only support conversion from/to "0" and "1". So my idea was to write my own conversion function which seems to work fine:
bool str_to_bool(const std::string &str)
{
if(str == "1" || str == "true" || str == "TRUE")
return true;
else if(str == "0" || str == "false" || str == "FALSE")
return false;
else
throw std::runtime_error("Bad cast from std::string to bool!");
}
Now I wan to write a wrapper round boost::lexical_cast and write my own template specializations for it. Here is what I've got so far:
template<typename Target, typename Source>
inline Target my_cast(const Source& src)
{
return boost::lexical_cast<Target>(src);
}
template<>
inline bool my_cast(const std::string& src)
{
return str_to_bool(src);
}
This works great for integers or std::string but obviously fails for string literals or character pointers:
int main(int argc, char* argv[])
{
std::cout << my_cast<bool>(1) << std::endl; //OK
std::cout << my_cast<bool>(std::string("true")) << std::endl; //OK
std::cout << my_cast<bool>("true") << std::endl; //Fail!
return 0;
}
So I tried to write another specialization for char * but it fails to compile!
//does not compile!
template<>
inline bool my_cast(const char*& src)
{
return str_to_bool(src);
}
What is the correct way to support both std::string and char *?
EDIT 1: the title was stupid. Fixed it.
EDIT 2: I borrowed a solution from boost itself. Posted as a new answer.
If you say this:
template<>
inline bool my_cast<bool, std::string>(std::string const & src)
{
return str_to_bool(src);
}
template<>
inline bool my_cast<bool, const char *>(const char * const & src)
{
return str_to_bool(src);
}
Then at least you can make the following work:
int main(int argc, char* argv[])
{
const char * const q = "true";
std::cout << my_cast<bool>(q) << std::endl; //Fail!
return 0;
}
Update: Voila:
typedef char FT[5];
template<>
inline bool my_cast<bool, FT>(const FT & src)
{
return str_to_bool(src);
}
Here is a solution that works. I got the idea from boost::lexical_cast itself:
template<class T>
struct array_to_pointer_decay
{
typedef T type;
};
template<class T, std::size_t N>
struct array_to_pointer_decay<T[N]>
{
typedef const T * type;
};
template<typename Target, typename Source>
Target my_cast_internal(const Source& s)
{
return boost::lexical_cast<Target>(s);
}
template<>
inline bool my_cast_internal(const std::string& src)
{
return str_to_bool(src);
}
template<>
inline bool my_cast_internal(const char* const& src)
{
return str_to_bool(src);
}
template<typename Target, typename Source>
inline Target my_cast(const Source& s)
{
typedef typename array_to_pointer_decay<Source>::type src;
return my_cast_internal<Target, src>(s);
}
The main challenge is to deal with array types. The array_to_pointer_decay converts any array type to the corresponding pointer type. The rest is easy now.
You need to take a const char*, not a const char*&. The mutable lvalue reference here will only bind to an lvalue, whereas the decay from the array type that the string literal actually is will only produce an rvalue const char*, to which you can only bind a const reference.
Let me add this as a new answer... a type-erasing version!
For C++98/03
/* Core caster */
bool str_to_bool(const std::string &str)
{
if(str == "1" || str == "true" || str == "TRUE")
return true;
else if(str == "0" || str == "false" || str == "FALSE")
return false;
else
throw std::runtime_error("Bad cast from std::string to bool!");
}
/* Type erasing scaffold */
struct TypeEraseBase
{
virtual bool cast() const = 0;
virtual ~TypeEraseBase() { }
};
template <typename T>
struct TypeEraseImpl : public TypeEraseBase
{
TypeEraseImpl(const T & tt) : t(tt) { }
virtual bool cast() const { return boost::lexical_cast<T>(t); }
private:
const T & t;
};
/* Specializations go here */
template <>
struct TypeEraseImpl<std::string> : public TypeEraseBase
{
TypeEraseImpl(const std::string & tt) : t(tt) { }
virtual bool cast() const { return str_to_bool(t); }
private:
const std::string & t;
};
template <size_t N>
struct TypeEraseImpl<char[N]> : public TypeEraseBase
{
TypeEraseImpl(const char (& tt)[N]) : t(tt) { }
virtual bool cast() const { return str_to_bool(std::string(t)); }
private:
const char (& t)[N];
};
template <>
struct TypeEraseImpl<const char *> : public TypeEraseBase
{
TypeEraseImpl(const char * const & tt) : t(tt) { }
virtual bool cast() const { return str_to_bool(std::string(t)); }
private:
const char * const & t;
};
/* User interface class */
struct my_cast
{
template <typename T> my_cast(const T & tt)
: pt(new TypeEraseImpl<T>(tt))
{
}
~my_cast() { if (pt) delete pt; }
inline bool cast() const { return pt->cast(); }
private:
const TypeEraseBase * const pt;
};
// Usage example
int main()
{
const char * const q = "true";
std::cout << my_cast(1).cast() << std::endl;
std::cout << my_cast(std::string("true")).cast() << std::endl;
std::cout << my_cast("true").cast() << std::endl;
std::cout << my_cast(q).cast() << std::endl;
return 0;
}
Type-traited version, templated return type
#include <string>
#include <stdexcept>
#include <iostream>
#include <ostream>
#include <boost/lexical_cast.hpp>
template <typename T> struct is_string : std::false_type { };
template <> struct is_string<std::string> : std::true_type { };
template <> struct is_string<const char *> : std::true_type { };
template <std::size_t N> struct is_string<char[N]> : std::true_type { };
/* The actual caster class */
template <typename T, bool B> struct to_bool
{
static inline bool cast(const T & t)
{
return boost::lexical_cast<T>(t);
}
};
template <typename T> struct to_bool<T, true>
{
static inline bool cast(const T & t)
{
const std::string str(t);
if(str == "1" || str == "true" || str == "TRUE")
return true;
else if(str == "0" || str == "false" || str == "FALSE")
return false;
else
throw std::runtime_error("Bad cast from std::string to bool!");
}
};
/* Type erasing helper class */
template <typename Target>
struct TypeEraseBase
{
virtual Target cast() const = 0;
virtual ~TypeEraseBase() { }
};
template <typename T, typename Target>
struct TypeEraseImpl : public TypeEraseBase<Target>
{
TypeEraseImpl(const T & tt) : t(tt) { }
virtual Target cast() const { return boost::lexical_cast<T>(t); }
private:
const T & t;
};
template <typename T>
struct TypeEraseImpl<T, bool> : public TypeEraseBase<bool>
{
TypeEraseImpl(const T & tt) : t(tt) { }
virtual bool cast() const { return to_bool<T, is_string<T>::value>::cast(t); }
private:
const T & t;
};
/* User interface class */
template <typename Target>
struct my_cast
{
template <typename T> my_cast(const T & tt)
: pt(new TypeEraseImpl<T, Target>(tt)) { }
~my_cast() { if (pt) delete pt; }
inline Target cast() const { return pt->cast(); }
private:
const TypeEraseBase<Target> * const pt;
};
template <typename Target>
std::ostream & operator<<(std::ostream & stream, const my_cast<Target> & c)
{ return stream << c.cast(); }
/* Usage */
int main()
{
const char * const q = "true";
std::cout << my_cast<bool>(1) << std::endl;
std::cout << my_cast<bool>(std::string("true")) << std::endl;
std::cout << my_cast<bool>("true") << std::endl;
std::cout << my_cast<bool>(q) << std::endl;
return 0;
}
Related
I'm trying to find a [better] way to run/check a potentially unsafe expression or perform multiple null checks in a more elegant way.
Here is an example of codes I would like to improve:
if (myObjectPointer &&
myObjectPointer->getSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) {
// Use safely target
... *(myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) ...
}
I tried to find a more elegant way to achieve this (instead of the above verbose null checks). Here is my first thoughts:
template<typename T>
bool isSafe(T && function) {
try {
function();
// Just running the func above, but we could e.g. think about returning the actual value instead of true/fase - not that important.
return true;
}
catch (...) {
return false;
}
}
...
// And use the above as follow :
if(isSafe([&](){ myObjectPointer->getSubObject()->getSubSubObject()->getTarget(); })) {
// Use safely target
}
...
The problem with the above is that we can't catch signals (Segmentation fault, ...). And I obviously don't want to handle all signals in the program, but only in this very specific check/eval function.
I'm I tackling the problem the wrong way ? Any other recommendations ? or the verbose if is inevitable ?
Many thanks in advance.
I was thinking about this, and like Jarod42 said, there must be some variadic template stuff. I'm not the best at this, but came up with this:
#include <memory>
#include <functional>
#include <iostream>
template <typename T, typename MemFn, typename... Params>
void safeExecute(T* ptr, MemFn memFn, Params&&... params) {
if (ptr != nullptr)
safeExecute(std::invoke(memFn, ptr), std::forward<Params>(params)...);
}
template <typename T, typename MemFn>
void safeExecute(T* ptr, MemFn memFn) {
if (ptr != nullptr) std::invoke(memFn, ptr);
}
struct Target {
void Bar() { std::cout << "tada!\n"; };
};
template<typename T>
class Object {
private:
std::unique_ptr<T> ptr;
public:
Object() : ptr(std::make_unique<T>()) {}
T* Get() { return ptr.get(); }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
int main() {
auto myObjectPtr = std::make_unique<MyObject>();
safeExecute(myObjectPtr.get(),
&MyObject::Get,
&SubObject::Get,
&SubSubObject::Get,
&Target::Bar);
}
edit:
I've been playing with the idea of having a more general return type, so I experimented with the option not to call the member function, but to return an std::optional pointer to the object. This lead me to the following code:
#include <memory>
#include <functional>
#include <iostream>
#include <optional>
template <typename T, typename MemFn, typename... Params>
auto safeGetObject(T* ptr, MemFn memFn, Params&&... params)
-> decltype(safeGetObject(std::invoke(memFn, std::declval<T>()), std::forward<Params>(params)...))
{
if (ptr != nullptr) return safeGetObject(std::invoke(memFn, ptr), std::forward<Params>(params)...);
return {};
}
template <typename T, typename MemFn>
auto safeGetObject(T* ptr, MemFn memFn) -> std::optional<decltype(std::invoke(memFn, std::declval<T>()))> {
if (ptr != nullptr) return std::invoke(memFn, ptr);
return {};
}
struct Target {
int Bar(int a, int b) const noexcept {
return a+b;
};
};
template<typename T>
class Object {
private:
std::unique_ptr<T> ptr;
public:
Object() noexcept : ptr(std::make_unique<T>()) {}
T* Get() const noexcept { return ptr.get(); }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
int main() {
auto myObjectPtr = std::make_unique<MyObject>();
auto optionalTarget = safeGetObject(
myObjectPtr.get(),
&MyObject::Get,
&SubObject::Get,
&SubSubObject::Get);
auto result = optionalTarget ? optionalTarget.value()->Bar(3, 4) : -1;
std::cout << " result " << result << '\n';
}
Putting possible design issues aside, you could use an extended version of std::optional. Since not all intefaces are under your control, you would have to wrap the functions were necessary into a free-function. Let's assume you can change the class MyClass of myObjectPointer, but not the classes of the sub-objects.
class MyClass {
public:
optional<std::reference_wrapper<SubObjectClass>> getSubObject();
};
optional<std::reference_wrapper<SubSubObjectClass>> getSubSubObject(SubObjectClass& s) {
SubSubObjectClass* ptr = s.getSubSubObject();
if (ptr) {
return std::ref(s.getSubSubObject());
} else {
return {};
}
}
optional<std::reference_wrapper<Target>> getTarget(SubSubObjectCLass& s) {
...
}
You can now write something like
optional<MyClass*> myObjectPointer = ...;
myObjectPointer.and_then(MyClass::getSubObject)
.and_then(getSubSubObject)
.and_then(getTarget)
.map( doSomethingWithTarget ):
OK, I might delete my previous answer, because I've been rethinking this, now considering using std::optional and chaining.
Your original
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()
is not really reproducible, since operator->() cannot be static. But we can use another operator, like operator>>(). Thus:
#include <memory>
#include <iostream>
#include <optional>
#include <functional>
struct Target {
int Bar(int a, int b) const noexcept { return a+b; };
};
template<typename T>
class Object {
private:
T* const ptr;
public:
Object(T* ptr) noexcept : ptr(ptr) {}
T* Get() const noexcept { return ptr; }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
template <typename T>
auto makeOptional(T* ptr) -> std::optional< std::reference_wrapper<T>> {
if (ptr) return std::ref(*ptr);
return {};
}
template <typename T, typename MemFn>
auto operator>> (std::optional<std::reference_wrapper<T>> optObj, MemFn memFn)
-> std::optional< std::reference_wrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>> {
if (optObj) return makeOptional(std::invoke(memFn, *optObj));
return {};
}
int main() {
{
//complete
auto TargetPtr = std::make_unique<Target>();
auto subSubObjectPtr = std::make_unique<SubSubObject>(TargetPtr.get());
auto subObjectPtr = std::make_unique<SubObject>(subSubObjectPtr.get());
auto myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto optionalMyObject = makeOptional(myObjectPtr.get());
auto optionalTarget = optionalMyObject >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto result = (optionalTarget) ? optionalTarget->get().Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
{
// incomplete
auto subObjectPtr = std::make_unique<SubObject>(nullptr);
auto myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto optionalMyObject = makeOptional(myObjectPtr.get());
auto optionalTarget = optionalMyObject >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto result = (optionalTarget) ? optionalTarget->get().Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
}
will work...
Let me know if this is what you're looking for.
edit:
I've also tried putting it in a wrapper class
#include <memory>
#include <iostream>
#include <functional>
#include <optional>
struct Target {
constexpr int Bar(int a, int b) const noexcept { return a + b; };
};
template<typename T>
class Object {
private:
T* const ptr;
public:
constexpr Object(T* const ptr) noexcept : ptr(ptr) {}
constexpr T* Get() const noexcept { return ptr; }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
template<typename T>
class ObjectWrapper {
private:
std::optional<std::reference_wrapper<T>> optRefObj{};
public:
constexpr ObjectWrapper(T* ptr) noexcept
: optRefObj(ptr ? std::make_optional(std::ref(*ptr)) : std::nullopt)
{}
template<typename MemFn>
constexpr auto operator>>(MemFn memFn) const noexcept {
return ObjectWrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>
(optRefObj ? std::invoke(memFn, *optRefObj) : nullptr);
}
constexpr operator bool() const noexcept { return optRefObj.has_value(); }
constexpr T* Get() noexcept { return optRefObj ? &optRefObj->get() : nullptr; }
};
int main() {
{
//complete
auto const TargetPtr = std::make_unique<Target>();
auto const subSubObjectPtr = std::make_unique<SubSubObject>(TargetPtr.get());
auto const subObjectPtr = std::make_unique<SubObject>(subSubObjectPtr.get());
auto const myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto const myObjWrp = ObjectWrapper(myObjectPtr.get());
auto optionalTarget = myObjWrp >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto const result = optionalTarget ? optionalTarget.Get()->Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
{
// incomplete
auto const subObjectPtr = std::make_unique<SubObject>(nullptr);
auto const myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto const myObjWrp = ObjectWrapper(myObjectPtr.get());
auto optionalTarget = myObjWrp >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto const result = optionalTarget ? optionalTarget.Get()->Bar(3, 4) : -1;
std::cout << "result is " << result << '\n';
}
}
Here's a fun challenge.
I wanted to created some boilerplate that allows the clean handling of precondition failures using syntax similar to perl's x or die("reason") approach.
I came up with this deleter:
struct do_exit {
[[noreturn]]
void operator()(void*) const noexcept {
std::exit(code_);
}
int code_;
};
Which we can use to manage the "deletion" of a temporary std::unique_ptr which is maybe pointing at std::cerr:
struct exit_stream
{
exit_stream(int code, std::ostream& os)
: stream_(std::addressof(os), do_exit { code })
{}
std::ostream& as_stream() const { return *stream_; }
operator bool() const { return bool(*stream_); }
template<class T>
friend auto operator<<(const exit_stream& es, T const& t) -> exit_stream const&
{
es.as_stream() << t;
return es;
}
std::unique_ptr<std::ostream, do_exit> stream_;
};
Created with the following function:
exit_stream die(int code = 100)
{
return exit_stream(code, std::cerr);
}
Now we can write the following program:
int main(int argc, char* argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]);
input or die(100) << "failed to open " << argv[1] << "\n";
}
This works because when the exit_stream is returned as a temporary, it must be moved (unique_ptr deletes the copy operator). unique_ptr guarantees that the moved-from pointer will be null. It also guarantees that the deleter will only be called if the unique_ptr is not null. Therefore, exit will only be called after all streaming operations have been executed at the call site.
However, the obvious failing is that I can't write:
auto input = std::ifstream(argv[1]]) or die() << "failed to open " << argv[1] << "\n";
Because if I did, input would be a bool.
Here's my question. Can you think of a way to produce the required effect, or as close to it as possible?
I really want to avoid this, for reasons of efficiency in the passing case, and for clarity and elegance:
auto input = (std::ifstream(argv[1]]) or die() << "failed to open " << argv[1] << "\n").get();
Full code:
#include <fstream>
#include <iostream>
#include <cstdlib>
struct do_exit {
[[noreturn]]
void operator()(void*) const noexcept {
std::exit(code_);
}
int code_;
};
struct exit_stream
{
exit_stream(int code, std::ostream& os)
: stream_(std::addressof(os), do_exit { code })
{}
std::ostream& as_stream() const { return *stream_; }
operator bool() const { return bool(*stream_); }
template<class T>
friend auto operator<<(const exit_stream& es, T const& t) -> exit_stream const&
{
es.as_stream() << t;
return es;
}
std::unique_ptr<std::ostream, do_exit> stream_;
};
exit_stream die(int code = 100)
{
return exit_stream(code, std::cerr);
}
int main(int argc, char* argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]);
input or die(100) << "failed to open " << argv[1];
}
OK, here's my first attempt. I'm a little concerned about redundant construction because of the lack of short-circuiting, but the syntax is what I wanted.
Comments / improvements welcome!
#include <fstream>
#include <iostream>
#include <utility>
#include <iomanip>
namespace detail {
struct tuple_emitter {
tuple_emitter(std::ostream &os) : os(os) {}
template<class...Refs>
void operator()(std::tuple<Refs...> const &t) const {
emit_impl(t, std::make_index_sequence<sizeof...(Refs)>());
}
private:
template<class T>
void emit_impl(T const &t) const {
os << t;
}
// make sure we handle lazy manipulators
void emit_impl(std::ios_base (* f)(std::ios_base &)) const
{
f(os);
}
template<class Tie, std::size_t...Is>
void emit_impl(Tie const &refs, std::index_sequence<Is...>) const {
using expand = int[];
void(expand{0,
((emit_impl(std::get<Is>(refs))), 0)...});
os << std::endl;
};
std::ostream &os;
};
// a class that emits a number of references to std::cerr and then
// exits
template<class...Refs>
struct dier {
dier(int code, std::tuple<Refs...> t) : code(code), emitter(std::cout), refs_(t) {}
template<class...Others, class Ref>
dier(dier<Others...> const &original, Ref const &r)
: code(original.code), emitter(original.emitter), refs_(std::tuple_cat(original.refs_, std::tie(r))) {};
void operator()() const {
emitter(refs_);
std::exit(code);
}
int code;
tuple_emitter emitter;
std::tuple<Refs&...> refs_;
};
template<class...Refs, class Ref>
auto operator<<(dier<Refs...> original, Ref const &ref) {
return dier<Refs..., const Ref &>(original, ref);
};
template<class T, class...Refs>
T operator||(T &&t, dier<Refs...> death) {
if (!t) {
death();
}
return std::move(t);
};
template<class T, class...Refs>
T const &operator||(T &t, dier<Refs...> death) {
if (!t) {
death();
}
return t;
};
}
auto die(int code = 100) {
return detail::dier<>(code, std::make_tuple());
}
int main(int argc, char *argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]) or die(5) << "failed to open " << std::setfill('-') << std::setw(10) << argv[1] << " and here is a hex number " << std::hex << 40;
}
Expected outputs:
With no arguments:
usage: myprog <inputfile>
With one argument "foo.txt":
failed to open ---foo.txt and here is a hex number 28
Update after Yakk's suggestions
got it down to this - which is much cleaner:
#include <fstream>
#include <iostream>
#include <utility>
#include <iomanip>
namespace notstd {
namespace detail {
template<class F, class T, std::size_t...Is>
void apply_impl(F&& f, T&& t, std::index_sequence<Is...>)
{
using expand = int[];
void(expand{0,
((f(std::get<Is>(t))), 0)...});
};
}
template<class F, class...Ts>
void apply(F&& f, std::tuple<Ts...> const& t)
{
detail::apply_impl(std::forward<F>(f), t, std::make_index_sequence<sizeof...(Ts)>());
};
struct apply_to_stream
{
apply_to_stream(std::ostream& os)
: os(os)
{}
template<class T>
std::ostream& operator()(T&& t) const
{
return os << t;
};
std::ostream& operator()(std::ios_base& (*f)(std::ios_base&)) const
{
f(os);
return os;
};
std::ostream& os;
};
}
namespace detail {
template<class Tuple>
struct dier {
constexpr dier(int code, Tuple t) : code(code), refs_(std::move(t)) {}
void operator()() const {
notstd::apply(notstd::apply_to_stream(std::cout), refs_);
std::cout << '\n';
std::exit(code);
}
int code;
Tuple refs_;
};
template<class Tie>
constexpr auto make_dier(int code, Tie&& t) {
return detail::dier<Tie>(code, std::forward<Tie>(t));
}
template<class Tuple, class Ref>
constexpr auto operator<<(dier<Tuple> original, Ref&& ref) {
return make_dier(original.code, std::tuple_cat(original.refs_, std::tie(ref)));
}
template<class T, class...Refs>
T operator||(T &&t, dier<Refs...> death) {
if (!t) {
death();
}
return std::forward<T>(t);
}
}
template<class Tie = std::tuple<>>
constexpr auto die(int code = 100, Tie&& t = {}) {
return detail::make_dier(code, std::forward<Tie>(t));
}
int main(int argc, char *argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]) or die(5) << "failed to open " << std::setfill('-') << std::setw(10) << argv[1] << " and here is a hex number " << std::hex << 40;
}
This is my attempt to improve #RichardHodges self answer.
First, some library esque code:
namespace notstd {
// takes a function object
// returns a function object that calls the first function object once for each argument
template<class F>
auto foreach( F&& f ) {
return [f=std::forward<F>(f)](auto&&...args)mutable{
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
}
// weak version of std::apply:
template<std::size_t...Is, class F, class Tuple>
decltype(auto) apply( std::index_sequence<Is...>, F&& f, Tuple&& tup) {
return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(tup))... );
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& tup) {
auto indexes = std::make_index_sequence< std::tuple_size< std::remove_reference_t<Tuple> >{} >{};
return apply(indexes, std::forward<F>(f), std::forward<Tuple>(tup) );
}
}
now we use it. This code is briefer due to the above:
namespace death {
namespace details {
template<class Tuple>
struct dier;
}
template<class Tuple=std::tuple<>>
details::dier<Tuple> die( int code, std::ostream& os = std::cerr, Tuple&& tuple={} ) {
return {code, os, std::forward<Tuple>(tuple)};
}
namespace details {
// a class that emits a number of references to std::cerr and then
// exits
template<class Tuple>
struct dier {
void operator()() const {
notstd::apply( notstd::foreach( [&](auto const&e){ os << e; } ), refs_ );
os << std::endl;
std::exit(code);
}
int code;
std::ostream& os;
Tuple refs_;
template<class Ref>
friend auto operator<<(dier&& original, Ref const &ref) {
return die( original.code, original.os, std::tuple_cat( std::move(original).refs_, std::tie(ref) ) );
}
template<class T>
friend T operator||(T &&t, dier&& death) {
if (!t) {
death();
}
return std::forward<T>(t);
}
};
}
}
auto die(int code = 100, std::ostream& os = std::cerr) {
return death::die(code, os);
}
Hope that helps.
Live example.
Note that all ... is eliminated except in the utility code.
I want template specilization with two parameters in one function. Here is a sample of code.
#include <iostream>
#include <string>
template <typename T>
class Printer
{
public:
T value;
Printer(T value)
{
this->value = value;
}
void print();
};
template <typename T> void Printer<T>::print()
{
std::cout << value << "\n";
}
template <> void Printer<std::string>::print()
{
std::cout << "\"" << value <<"\"\n";
}
template <> void Printer<const char *>::print()
{
std::cout << "\"" << value <<"\"\n";
}
int main()
{
Printer<int> print1(2);
Printer<std::string> print2("Printing string");
Printer<const char *> print3("Printing char*");
print1.print();
print2.print();
print3.print();
}
Is there a way I can make the template speciazation for std::string and const char * in one function. I want this because they are doing the same thing.
You can use traits to add indirection on the specific behavior, based on type.
#include <iostream>
#include <string>
template <typename T>
class Printer
{
public:
T value;
Printer(T value)
{
this->value = value;
}
void print();
};
template<typename T>
struct PrinterTypeTraits {
static constexpr char* prefix = "";
static constexpr char* postfix = "";
};
template<>
struct PrinterTypeTraits<std::string> {
static constexpr char prefix = '\"';
static constexpr char postfix = '\"';
};
template<>
struct PrinterTypeTraits<const char*> : PrinterTypeTraits<std::string> {};
template <typename T> void Printer<T>::print()
{
using Traits = PrinterTypeTraits<T>;
std::cout << Traits::prefix << value << Traits::postfix << '\n';
}
int main()
{
Printer<int> print1(2);
Printer<std::string> print2("Printing string");
Printer<const char *> print3("Printing char*");
print1.print();
print2.print();
print3.print();
return 0;
}
The code below allows me to template a function
taking a parameter which is a vector of one of three different pointer types to Box objects:
const std::vector<std::shared_ptr<Box>>&
const std::vector<std::weak_ptr<Box>>&
const std::vector<Box*>&
Is there a way to extend this to support:
const vector<Box>&
const vector<std::reference_wrapper<Box>>
perhaps something in boost?
#include <vector>
#include <iostream>
class Box{
public:
Box (unsigned int id, unsigned int side): id(id), side(side){}
int volume(){
return side * side * side;
}
unsigned int id;
unsigned int side;
};
template <typename T>
struct is_box_containter {
enum { value = false };
};
template <>
struct is_box_containter <std::vector<std::shared_ptr<Box>>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<std::weak_ptr<Box>>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<Box*>> {
enum { value = true };
};
template <typename T>
typename std::enable_if<is_box_containter<T>::value>::type
measure(T const& boxes )
{
for (auto& box : boxes) {
std::cout << box->id << " has volume " << box->volume() << std::endl;
}
}
int main (){
std::vector<std::shared_ptr<Box>> some_boxes;
some_boxes.push_back(std::shared_ptr<Box>(new Box(1,4)));
some_boxes.emplace_back(new Box(2, 12));
Box * box_3 = new Box(3, 8);
Box * box_4 = new Box(4, 9);
std::vector<Box*> more_boxes;
more_boxes.emplace_back(box_3);
more_boxes.emplace_back(box_4);
measure(some_boxes);
measure(more_boxes);
return 0;
}
Why I am asking this question:
I have an application with two functions which implement near identical logic. One takes a list of SomeClass, the other takes a vector of pointers to SomeClass.
I am currently planning on refactoring the code to replace the list of SomeClass with a list of shared pointers to SomeClass. But the only reason I am doing this is to move the logic to a common implementation. I don't want to do that if there is a perfectly reasonable way to avoid it.
If I understood your question correctly, you could use a dereferencing mechanism like below:
template<typename T>
T& dereference(T &v) {
return v;
}
template<typename T>
const T& dereference(const T& v) {
return v;
}
template<typename T>
typename std::enable_if<!std::is_function<T>::value, T&>::type dereference(T* v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::shared_ptr<T>& v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::weak_ptr<T>& v) {
return dereference(*v);
}
template<typename T>
const T& dereference(const std::reference_wrapper<T>& v) {
return v;
}
and then call your data like:
template <typename T>
typename std::enable_if<is_box_containter<T>::value>::type
measure(T const& boxes )
{
for (auto& box : boxes) {
std::cout << dereference(box).id
<< " has volume " << dereference(box).volume() << std::endl;
}
}
LIVE DEMO
P.S You'll also have to define:
template <>
struct is_box_containter <std::vector<Box>> {
enum { value = true };
};
template <>
struct is_box_containter <std::vector<std::reference_wrapper<Box>>> {
enum { value = true };
};
I am trying to write a XML serializer and de-serializer for user defined classes. Please refer to the code posted in Coliru
The deserializer i am unable to get the type resolved from the adt_proxy to the value type in question. The error is the read_handle function. Can anyone tell me what I am missing here ?
static inline void read_handle(FusionVisitorConcept& visitor, S& s)
{
visitor.start_member(name_t::call());
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, boost::fusion::at<N>(s));
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::read_handle(visitor, s);
}
Indeed the ADT proxies are ruining the party here. It's the Law of Leaky Abstractions.
In particular, you can't deserialize a boost::lazy_disable_if_c<false, boost::fusion::result_of::at<Bar, mpl_::int_<0> > >::type. Now, if you replace
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, boost::fusion::at<N>(s));
with
current_t tmp;
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, tmp);
boost::fusion::at<N>(s) = tmp;
It works. There's a side-effect though: now current_t needs to be default-constructible.
Here's the fully working sample
Live On Coliru
#include <typeinfo>
#include <string>
#include <iostream>
#include <sstream>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/intrinsic.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/adt.hpp>
#include <boost/optional.hpp>
#include <boost/lexical_cast.hpp>
class Bar {
int integer_value;
public:
Bar(int i_val=0):integer_value(i_val) { }
int get_integer_value() const { return integer_value; }
void set_integer_value(int i_val) { integer_value = i_val; }
};
class Foo {
Bar bar_value;
public:
Foo(int i_val=0):bar_value(i_val) { }
Bar get_bar_value() const { return bar_value; }
void set_bar_value(const Bar b_val) { bar_value = b_val; }
};
BOOST_FUSION_ADAPT_ADT(Bar,
(int, int, obj.get_integer_value(), obj.set_integer_value(val)))
BOOST_FUSION_ADAPT_ADT(Foo,
(Bar, Bar, obj.get_bar_value(), obj.set_bar_value(val)))
#define MY_ADT_MEMBER_NAME(CLASSNAME, IDX, MEMBERNAME) \
namespace boost { namespace fusion { namespace extension { \
template <> struct struct_member_name<CLASSNAME, IDX> { typedef char const *type; static type call() { return #MEMBERNAME; } \
}; } } }
MY_ADT_MEMBER_NAME(Bar, 0, integer_value)
MY_ADT_MEMBER_NAME(Foo, 0, bar_value)
namespace visitor {
template <typename Flavour, typename T> struct VisitorApplication;
namespace detail
{
template <typename V, typename Enable = void>
struct is_vector : boost::mpl::false_ { };
template <typename T>
struct is_vector<std::vector<T>, void> : boost::mpl::true_ { };
namespace iteration
{
// Iteration over a sequence
template <typename FusionVisitorConcept, typename S, typename N>
struct members_impl
{
// Type of the current member
typedef typename boost::fusion::result_of::value_at<S, N>::type current_t;
typedef typename boost::mpl::next<N>::type next_t;
typedef boost::fusion::extension::struct_member_name<S, N::value> name_t;
static inline void handle(FusionVisitorConcept& visitor, const S& s)
{
visitor.start_member(name_t::call());
VisitorApplication<FusionVisitorConcept, current_t>::handle(visitor, boost::fusion::at<N>(s));
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::handle(visitor, s);
}
static inline void read_handle(FusionVisitorConcept& visitor, S& s)
{
visitor.start_member(name_t::call());
current_t tmp;
VisitorApplication<FusionVisitorConcept, current_t>::read_handle(visitor, tmp);
boost::fusion::at<N>(s) = tmp;
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::read_handle(visitor, s);
}
};
// End condition of sequence iteration
template <typename FusionVisitorConcept, typename S>
struct members_impl<FusionVisitorConcept, S, typename boost::fusion::result_of::size<S>::type>
{
static inline void handle(FusionVisitorConcept const&, const S&) { /*Nothing to do*/ }
static inline void read_handle(FusionVisitorConcept const&, S&) { /*Nothing to do*/ }
};
// Iterate over struct/sequence. Base template
template <typename FusionVisitorConcept, typename S>
struct Struct : members_impl<FusionVisitorConcept, S, boost::mpl::int_<0>> {};
} // iteration
template <typename FusionVisitorConcept, typename T>
struct array_application
{
typedef array_application<FusionVisitorConcept, T> type;
typedef typename T::value_type value_type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_array();
for (auto& el : t)
VisitorApplication<FusionVisitorConcept, value_type>::handle(visitor, el);
}
static inline void read_handle(FusionVisitorConcept& visitor, T& t)
{
visitor.empty_array();
for (auto& el : t)
VisitorApplication<FusionVisitorConcept, value_type>::read_handle(visitor, el);
}
};
template <typename FusionVisitorConcept, typename T>
struct struct_application
{
typedef struct_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_object();
iteration::Struct<FusionVisitorConcept, T>::handle(visitor, t);
}
static inline void read_handle(FusionVisitorConcept& visitor, T& t)
{
iteration::Struct<FusionVisitorConcept, T>::read_handle(visitor, t);
}
};
template <typename FusionVisitorConcept, typename T, typename Enable = void>
struct value_application
{
typedef value_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t) {
visitor.value(t);
}
static inline void read_handle(FusionVisitorConcept& visitor, T& t) {
visitor.value(t);
}
};
template <typename FusionVisitorConcept, typename T>
struct value_application<FusionVisitorConcept, boost::optional<T> >
{
typedef value_application<FusionVisitorConcept, boost::optional<T> > type;
static inline void handle(FusionVisitorConcept& visitor, const boost::optional<T>& t) {
if (t)
VisitorApplication<FusionVisitorConcept, T>::handle(visitor, *t);
else
; // perhaps some default action?
}
static inline void read_handle(FusionVisitorConcept& visitor, boost::optional<T>& t) {
if (t)
VisitorApplication<FusionVisitorConcept, T>::read_handle(visitor, *t);
else
; // perhaps some default action?
}
};
template <typename FusionVisitorConcept, typename T>
struct select_application
{
typedef
//typename boost::mpl::eval_if<boost::is_array<T>, boost::mpl::identity<array_application<FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<detail::is_vector<T>, boost::mpl::identity<array_application <FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<boost::fusion::traits::is_sequence<T>, boost::mpl::identity<struct_application<FusionVisitorConcept, T>>,
boost::mpl::identity<value_application<FusionVisitorConcept, T>>
> >::type type;
};
} // detail
template <typename FusionVisitorConcept, typename T>
struct VisitorApplication : public detail::select_application<FusionVisitorConcept, T>::type
{
};
}
template <typename FusionVisitorConcept, typename T>
void apply_fusion_visitor(FusionVisitorConcept& visitor, T const& o)
{
visitor::VisitorApplication<FusionVisitorConcept, T>::handle(visitor, o);
}
template <typename FusionVisitorConcept, typename T>
void apply_read_fusion_visitor(FusionVisitorConcept& visitor, T & o)
{
visitor::VisitorApplication<FusionVisitorConcept, T>::read_handle(visitor, o);
}
struct DisplayMemberVisitor {
typedef std::string result_type;
DisplayMemberVisitor() { ss << std::boolalpha; }
std::string complete() { return ss.str(); }
void start_member (const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
ss << "<" << name << ">";
}
void finish_member(const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
ss << "</" << name << ">";
}
template <typename T> void value(T const& value) {
std::cerr << __PRETTY_FUNCTION__ << ":\t" << value << "\n";
ss << value;
}
//template <typename T> void value(boost::optional<T>& value);
void empty_object() { std::cerr << __PRETTY_FUNCTION__ << "\n"; }
void empty_array() { std::cerr << __PRETTY_FUNCTION__ << "\n"; }
private:
std::stringstream ss;
};
struct ReadMemberVisitor {
typedef std::string result_type;
ReadMemberVisitor(std::string ss_) { ss = ss_; }
void start_member (const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
std::string tag = "<" + std::string(name) + ">";
ss = ss.substr(tag.length(),ss.length());
}
void finish_member(const char* name) {
std::cerr << __PRETTY_FUNCTION__ << ":\t'" << name << "'" << "\n";
std::string tag = "</" + std::string(name) + ">";
ss = ss.substr(tag.length(),ss.length());
}
template <typename T> void value(T &value) {
auto pos = ss.find('<');
std::string value_string = ss.substr(0,pos);
std::cerr << __PRETTY_FUNCTION__ << " -> '" << value_string << "'\n";
value = boost::lexical_cast<T>(value_string);
ss = ss.substr(pos,ss.length());
}
private:
std::string ss;
};
int main()
{
// Bar
{
Bar b(8);
DisplayMemberVisitor vis;
apply_fusion_visitor(vis, b);
std::cout << "\n" << vis.complete() << "\n";
Bar cloned;
ReadMemberVisitor rv(vis.complete());
apply_read_fusion_visitor(rv, cloned);
}
std::cout << "\n-----------\n";
// Foo
Foo const f{78};
std::string f_serialized;
{
DisplayMemberVisitor vis;
apply_fusion_visitor(vis, f);
f_serialized = vis.complete();
std::cout << "\n" << f_serialized << "\n";
}
std::cout << "\n-----------\n";
Foo cloned{0};
ReadMemberVisitor rv(f_serialized);
apply_read_fusion_visitor(rv, cloned);
std::cout << "\n-----------\n";
std::cout << f.get_bar_value().get_integer_value() << " == " << cloned.get_bar_value().get_integer_value() << "\n";
}
Output:
void DisplayMemberVisitor::empty_object()
void DisplayMemberVisitor::start_member(const char*): 'integer_value'
void DisplayMemberVisitor::value(const T&) [with T = int]: 8
void DisplayMemberVisitor::finish_member(const char*): 'integer_value'
<integer_value>8</integer_value>
void ReadMemberVisitor::start_member(const char*): 'integer_value'
void ReadMemberVisitor::value(T&) [with T = int] -> '8'
void ReadMemberVisitor::finish_member(const char*): 'integer_value'
-----------
void DisplayMemberVisitor::empty_object()
void DisplayMemberVisitor::start_member(const char*): 'bar_value'
void DisplayMemberVisitor::empty_object()
void DisplayMemberVisitor::start_member(const char*): 'integer_value'
void DisplayMemberVisitor::value(const T&) [with T = int]: 78
void DisplayMemberVisitor::finish_member(const char*): 'integer_value'
void DisplayMemberVisitor::finish_member(const char*): 'bar_value'
<bar_value><integer_value>78</integer_value></bar_value>
-----------
void ReadMemberVisitor::start_member(const char*): 'bar_value'
void ReadMemberVisitor::start_member(const char*): 'integer_value'
void ReadMemberVisitor::value(T&) [with T = int] -> '78'
void ReadMemberVisitor::finish_member(const char*): 'integer_value'
void ReadMemberVisitor::finish_member(const char*): 'bar_value'
-----------
78 == 78