clean, functional script-like error handling in c++ - c++

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.

Related

Template with fold expression creates unwanted parameter copy

The following prototype is intended to make synchronized print:
#include <iostream>
#include <string>
#include <sstream>
#include <mutex>
#include <Windows.h> // for OutputDebugString
std::mutex sync_mutex;
template<typename T>
void sync_print_impl(std::ostringstream& str, const T& t)
{
str << t << " ";
}
template<typename ... Args>
void sync_print_impl(std::ostringstream& str, Args ... args)
{
str; // prevents unused variable warning when sync_print is called without arguments
(..., sync_print_impl(str, args));
}
template <typename... Args>
void sync_print(Args... args)
{
std::ostringstream s;
sync_print_impl(s, args...);
{
std::lock_guard<std::mutex> lg(sync_mutex);
std::cout << s.str() << std::endl;
}
}
Simple test is OK:
void test1()
{
sync_print("abc", 1, 5.5); // prints abc 1 5.5
sync_print(); // prints empty string
}
The following test shows, that parameters are copied:
class test_class
{
public:
test_class(int n)
: data(n)
{
OutputDebugString(L"test_class\n");
}
test_class(const test_class& other)
{
data = other.data;
OutputDebugString(L"copy constructor\n");
}
test_class& operator=(const test_class& other)
{
data = other.data;
OutputDebugString(L"operator=\n");
return *this;
}
~test_class()
{
OutputDebugString(L"~test_class\n");
}
friend std::ostream& operator<<(std::ostream& os, const test_class& t);
private:
int data{};
};
std::ostream& operator<<(std::ostream& os, const test_class& t)
{
os << t.data;
return os;
}
void test2()
{
test_class t(5);
sync_print(t); // prints 5
}
OutputDebugString result is:
test_class
copy constructor
~test_class
~test_class
How to change sync_print to ensure that parameters are passed by reference?
You do not need extra template function sync_print_impl. Following should be enough, as you can make use of c++17 's fold expression.
In addition, use perfect forwarding to avoid coping the object.
template<typename... Args>
void sync_print_impl(std::ostringstream& str, Args&&... args)
// ^^^^^^^^^^^^^^^^
{
((str << std::forward<Args>(args) << " "), ...);
}
template <typename... Args>
void sync_print(Args&&... args)
// ^^^^^^^^^^^^^^^
{
std::ostringstream s;
sync_print_impl(s, std::forward<Args>(args)...);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ... code
}

is there a std::optional_function like the given

I am searching for something like swifts ? operator in c++ for std::function. I have grown to like it over the last couple years.
I would like a std::optional_function, which only calls the function if the function exists.
Something like this (but written by the gods of c++):
template<typename R>
struct option_function_result {
bool executed;
R result;
} ;
template<>
struct option_function_result<void>
{
bool executed;
} ;
template<typename F>
class optional_function
{
public:
typedef std::function<F> function_type;
typedef option_function_result<typename function_type::result_type> result_type;
protected:
function_type f;
public:
template<typename Fn>
optional_function operator=(const Fn &f_)
{
f = f_;
return *this;
}
template<typename Fn>
optional_function operator=(Fn &&f_)
{
f = std::forward<Fn>(f_);
return *this;
}
operator bool() const
{
return (bool)f;
}
template<typename ...Args, typename R>
result_type operator()(Args... args)
{
if (f)
return result_type { true, f(args...) };
return result_type { false };
}
template<typename ...Args>
result_type operator()(Args... args)
{
if (f)
{
f(args...);
return result_type { true };
}
return result_type { false };
}
} ;
Another revision
Here is revision 2. In order not to polute the question, and since I don't know if this will be a final answer, I'm gonna place it here for now:
I expect that the constructor for the struct is not necessary. However it forces the compiler to give me errors I need to debug the compilation.
template<typename R>
struct optional_function_result {
bool executed;
R result;
optional_function_result(bool &&executed_, R &&result_) :
executed (executed_),
result(result_) {}
} ;
template<>
struct optional_function_result<void>
{
bool executed;
optional_function_result(bool &&executed_) :
executed (executed_) {}
} ;
template<typename F>
class optional_function
{
public:
typedef std::function<F> function_type;
typedef typename std::function<F>::result_type function_result_type;
typedef optional_function_result<typename function_type::result_type> result_type;
protected:
function_type f;
public:
template<typename Fn>
optional_function operator=(const Fn &f_)
{
f = f_;
return *this;
}
template<typename Fn>
optional_function operator=(Fn &&f_)
{
f = std::forward<Fn>(f_);
return *this;
}
operator bool() const
{
return (bool)f;
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<!std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
return {
true,
std::forward<typename function_type::result_type>(f(args...))
};
return {
false,
function_result_type()
};
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
{
f(args...);
return { true };
}
return { false };
}
} ;
Ok one more version, which uses basically optional to get rid of some edge cases.
template<typename T>
using optional_type = std::experimental::optional<T>;
template<typename R>
struct optional_function_result : optional_type<R> {
typedef optional_type<R> super_type;
optional_function_result() :
super_type() {}
optional_function_result(R &&result_) :
super_type(result_) {}
bool executed() const { return this->has_result(); }
} ;
template<>
struct optional_function_result<void>
{
bool executed_;
optional_function_result(bool &&executed__) :
executed_ (executed__) {}
bool executed() const { return executed_; }
} ;
template<typename F>
class optional_function
{
public:
typedef std::function<F> function_type;
typedef typename std::function<F>::result_type function_result_type;
typedef optional_function_result<typename function_type::result_type> result_type;
protected:
function_type f;
public:
template<typename Fn>
optional_function operator=(const Fn &f_)
{
f = f_;
return *this;
}
template<typename Fn>
optional_function operator=(Fn &&f_)
{
f = std::forward<Fn>(f_);
return *this;
}
operator bool() const
{
return (bool)f;
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<!std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
return {
std::forward<typename function_type::result_type>(f(args...))
};
return {};
}
template<
typename ... Args,
typename FR=function_result_type,
typename std::enable_if<std::is_void<FR>::value, FR>::type* = nullptr
>
result_type operator()(Args... args) const
{
if (f)
{
f(args...);
return { true };
}
return { false };
}
} ;
The ? operator works really well in C++ too:
// let function be of type std::function or a function pointer
auto var = f ? f() : default_value;
If you really want a type that does that, there is no such thing in the standard library, but a simple function is enough to do what you want (works only for function that don't return references or void):
template<typename F, typename... Args, typename R = std::invoke_result_t<F, Args&&...>>
auto optionally_call(F&& f, Args&&... args) -> std::optional<R> {
return f ? R(std::forward<F>(f)(std::forward<Args>(args)...)) : std::nullopt;
}
With some metaprogramming, it's possible to support cases not supported by this implementation.
This is to highlight that there's a lot of pitfalls when creating a whole type that is meant to be generic. There are many mistakes and performance issues and even code that will cannot be called in your sample code. A simple utility function would be easier than a type.
The standard library doesn't have anything like that, but you can build one yourself:
#include <functional>
#include <iostream>
#include <optional>
template <typename T>
class optional_function {
private:
std::optional<T> func;
public:
optional_function(T f) : func{std::move(f)} {}
optional_function() = default;
template <typename... Args>
auto operator()(Args&&... args) const {
using func_invoke_type = decltype((*func)(std::forward<Args>(args)...));
constexpr bool func_invoke_type_is_void = std::is_same_v<void, func_invoke_type>;
using optional_result_type = std::optional<
std::conditional_t<
func_invoke_type_is_void, // Can't have a std::optional<void>
char,
std::conditional_t<
std::is_reference_v<func_invoke_type>, // Can't have a std::optional<T&>
std::reference_wrapper<std::remove_reference_t<func_invoke_type>>,
func_invoke_type
>
>
>;
if (func) {
if constexpr (!func_invoke_type_is_void) {
return optional_result_type{(*func)(std::forward<Args>(args)...)};
} else {
(*func)(std::forward<Args>(args)...);
return optional_result_type{ '\0' }; // can't return void{} '
}
}
return optional_result_type{};
}
};
// Test it
void foo() {}
int main() {
optional_function f1{[](int i) { return i * i; }};
optional_function f2{[] { std::cout << "Hello World\n"; }};
decltype(f1) f3{};
optional_function f4{[](int a, const int& b) -> int const& {
std::cout << a + b << '\n';
return b;
}};
optional_function f5{foo};
auto res1 = f1(9);
auto res2 = f2();
auto res3 = f3(9);
int b = 5;
auto res4 = f4(1, b);
auto res5 = f5();
std::cout << std::boolalpha;
std::cout << "f1 is executed: " << res1.has_value() << ". result: " << *res1
<< '\n';
std::cout << "f2 is executed: " << res2.has_value() << '\n';
std::cout << "f3 is executed: " << res3.has_value() << '\n';
std::cout << "f4 is executed: " << res4.has_value() << ". result: " << *res4
<< '\n';
std::cout << "f5 is executed: " << res5.has_value() << '\n';
}
No, there is currently no such thing in the C++ Standard Library.

boost::typeindex::type_id<T>().pretty_name() is not "pretty"

I am trying to have the type of some variable printed on stdout. This code:
std::string mystr {"dsadsadas"};
std::cout << boost::typeindex::type_id< decltype(mystr) >().pretty_name() << std::endl;
results in:
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1:: allocator<char> >
which is definitely not pretty.. why is this happening? any workaround?? (Note I'm compiling with clang++ using c++14 semantics)
I have a library called cpputil (privately maintained on bitbucket) which has lots of useful shortcuts for c++11 or better.
one of the concepts is cpputil::classname_of(x).
The idea is that if a class has a static member data or function called classname, this is used to print the name of the class. If not, you can supply a free function that provides the classname. Failing that, typeid.name() is used as a fallback.
Now your classnames can be as pretty as you like.
Live On Coliru
#include <iostream>
#include <type_traits>
/// static member of any type
namespace cpputil {
namespace detail {
template<class T>
constexpr auto has_static_member_classname(...)
-> std::false_type
{
return {};
}
template<class T>
constexpr auto has_static_member_classname(int)
-> decltype(T::classname, void(), std::true_type())
{
return {};
}
// static member of type function that returns anything but takes no args
template<class T>
constexpr auto has_static_function_classname(...)
-> std::false_type
{ return {}; }
template<class T>
constexpr auto has_static_function_classname(int)
-> decltype(T::classname(), void(), std::true_type())
{ return {}; }
}
// templated free function that takes no args, used as a fallback but may be overriden
template<class T> decltype(auto) classname() { return typeid(T).name(); }
namespace detail {
template<class T>
constexpr auto has_free_function_classname_0(...)
-> std::false_type
{ return {}; }
template<class T>
constexpr auto has_free_function_classname_0(int)
-> decltype(classname<T>(), void(), std::true_type())
{ return {}; }
// free function that takes a const ref
template<class T>
constexpr auto has_free_function_classname_1(...)
-> std::false_type
{ return {}; }
template<class T>
constexpr auto has_free_function_classname_1(int)
-> decltype(classname(std::declval<T>()), void(), std::true_type())
{ return {}; }
template<class T, typename = void>
struct classname_finder;
// highest priority - if there is a free function taking 1 parameter findable by ADL - use this
template<class T>
struct classname_finder<
T,
std::enable_if_t<
decltype(has_free_function_classname_1<T>(0))::value
>
>
{
static constexpr decltype(auto) apply() { return classname(*reinterpret_cast<const T*>(0)); }
static constexpr decltype(auto) apply(const T& t) { return classname(t); }
};
// priority 2 - if there is a static function, use that
template<class T>
struct classname_finder<
T,
std::enable_if_t<
decltype(has_static_function_classname<T>(0))::value &&
!decltype(has_free_function_classname_1<T>(0))::value
>
>
{
static constexpr decltype(auto) apply() { return T::classname(); }
static constexpr decltype(auto) apply(const T&) { return T::classname(); }
};
// priority 3 - if there is a static data member, use that
template<class T>
struct classname_finder<
T,
std::enable_if_t<
decltype(has_static_member_classname<T>(0))::value &&
!decltype(has_static_function_classname<T>(0))::value &&
!decltype(has_free_function_classname_1<T>(0))::value
>
>
{
static constexpr decltype(auto) apply() { return T::classname; }
static constexpr decltype(auto) apply(const T&) { return T::classname; }
};
// finally, use the cpputil::classname_of<X>() template overload
template<class T>
struct classname_finder<
T,
std::enable_if_t<
!decltype(has_static_member_classname<T>(0))::value &&
!decltype(has_static_function_classname<T>(0))::value &&
!decltype(has_free_function_classname_1<T>(0))::value &&
decltype(has_free_function_classname_0<T>(0))::value
>
>
{
static constexpr decltype(auto) apply() { return classname<T>(); }
static constexpr decltype(auto) apply(const T&) { return classname<T>(); }
};
}
template<class T>
auto classname_of(const T& t)
{
return detail::classname_finder<T>::apply(t);
}
template<class T>
auto classname_of()
{
return detail::classname_finder<T>::apply();
}
}
struct class_a
{
static const char* classname() { return "class_a"; }
};
struct class_b
{
constexpr static const char* classname = "class_b";
};
struct class_c
{
};
namespace cpputil {
template<> decltype(auto) classname<class_c>() { return "class_c"; }
}
struct class_d
{
};
decltype(auto) classname(const class_d&) { return "class_d"; }
struct class_e {
static const std::string& classname() { static const std::string _("class_e static function"); return _; }
};
static const char* classname(const class_e&) {
return "class_e free function should take priority";
}
// no classname decoration. should fall back to typeid() solution
struct class_f {
};
using namespace std;
auto main() -> int
{
class_a a;
class_b b;
class_c c;
class_d d;
class_e e;
class_f f;
cout << cpputil::classname_of(a) << endl;
cout << cpputil::classname_of(b) << endl;
cout << cpputil::classname_of(c) << endl;
cout << cpputil::classname_of(d) << endl;
cout << cpputil::classname_of(e) << endl;
cout << cpputil::classname_of(f) << endl;
cout << endl;
cout << cpputil::classname_of<class_a>() << endl;
cout << cpputil::classname_of<class_b>() << endl;
cout << cpputil::classname_of<class_c>() << endl;
cout << cpputil::classname_of<class_d>() << endl;
cout << cpputil::classname_of<class_e>() << endl;
cout << cpputil::classname_of<class_f>() << endl;
return 0;
}
Prints
class_a
class_b
class_c
class_d
class_e free function should take priority
7class_f
class_a
class_b
class_c
class_d
class_e free function should take priority
7class_f

boost bind variadics overload resolution

#include <cstdio>
#include <string>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
struct CLASS{
template<typename T, typename ... Args>
void enqueue(T const & t, Args const & ... args){
this->concatenate(t,args ...);
}
template<typename T, typename ... Args>
void concatenate(T t, Args ... args){
boost::function<void()> f
= boost::bind(&CLASS::push_,this,
boost::bind(&CLASS::stringer<T const &,
Args const & ...>,
this,boost::ref(t),boost::ref(args)...));
}
template<typename T, typename ... Args>
std::string stringer(T const & t, Args const & ... args){
return stringer(t) + stringer(args...);
}
template <typename T>
std::string stringer(T const & t){
return boost::lexical_cast<std::string>(t);
}
void push_(std::string const & s){
std::fprintf(stderr,"%s\n",s.c_str());
}
};
int main(){
CLASS c;
c.enqueue(42,"hello",35);
// below commented enqueue fails to compile
//c.enqueue("abc", 100," for ", 42000,"sadada ", 4.3, "zzzzz\n",42,42);
return 0;
}
In the main function above, the commented line fails to compile, although the uncommented enqueue does work. I have a feeling the problem is to do with the unwinding of the variadics by the stringer function and boost::bind failing to figure out overloads or something.
How do I solve this problem, so that enqueue works for any combination of inputs?
under c++11,we cannot bind a overload function.
but there is solution under C++14:
example:
struct ulong_ip_tag{};
struct string_ip_tag{};
struct resolved_ip_tag{};
struct invalid_ip_tag{};
template<typename _Type, typename _Handler>
void handler(_Handler, _Type)
{
std::cout << "other type" << std::endl;
}
template<typename _Handler>
void handler(_Handler, resolved_ip_tag)
{
std::cout << typeid(resolved_ip_tag).name() << std::endl;
}
template<typename _Handler>
void handler(_Handler, string_ip_tag)
{
std::cout << typeid(string_ip_tag).name() << std::endl;
}
template<typename _Handler>
void handler(_Handler, ulong_ip_tag)
{
std::cout << typeid(ulong_ip_tag).name() << std::endl;
}
void test(){}
int main()
{
//auto--- under c++14
auto b = [](auto arg1,auto arg2){handler(arg1,arg2)};
std::bind(b,test,ulong_ip_tag());
}

how to generate code to initialize a std::vector with a custom Zero value if it exists as T::Zero?

BACKGROUND
I have a container class that has a std::vector<T> member that I initialize with the constructor that takes size_t n_items. I would like to initialize that vector with my own Zero() function which returns 0; by default, but if static member T::Zero exists I want to return that instead.
In my first attempt, I use expression SFINAE, but that failed due to ambiguous overload since both the generic version of Zero and the Zero have the same signature with no arguments. So now, I'm trying to convert the code into classes with operator().
I think I need to use std::enable_if somehow, but I'm not sure how to go about coding this.
FAILED ATTEMPT
#include <cassert>
#include <iostream>
#include <vector>
template<typename T>
struct Zero
{
T operator() const { return 0; }
};
template<typename T>
struct Zero
{
auto operator() const ->
decltype( T::Zero )
{
return T::Zero;
}
};
struct Foo
{
char m_c;
static Foo Zero;
Foo() : m_c( 'a' ) { }
Foo( char c ) : m_c( c ) { }
bool operator==( Foo const& rhs ) const { return m_c==rhs.m_c; }
friend std::ostream& operator<<( std::ostream& os, Foo const& rhs )
{
os << (char)(rhs.m_c);
return os;
}
};
Foo Foo::Zero( 'z' );
int
main( int argc, char** argv )
{
std::vector<unsigned> v( 5, Zero<unsigned>() );
std::vector<Foo> w( 3, Zero<Foo>() );
for( auto& x : v )
std::cout << x << "\n";
std::cout << "---------------------------------\n";
for( auto& x : w )
{
assert( x==Foo::Zero );
std::cout << x << "\n";
}
std::cout << "ZERO = " << Foo::Zero << "\n";
return 0;
}
#include <string>
#include <iostream>
#include <vector>
#include <type_traits>
namespace detail
{
template<class T, class = decltype(T::zero)>
std::true_type has_zero_impl(int);
template<class T>
std::false_type has_zero_impl(short);
}
template<class T>
using has_zero = decltype(detail::has_zero_impl<T>(0));
template<class T, class = has_zero<T>>
struct zero
{
constexpr static T get() { return T(); }
};
template<class T>
struct zero<T, std::true_type>
{
constexpr static auto get() -> decltype(T::zero)
{ return T::zero; }
};
Usage example:
template<>
struct zero<std::string>
{
static constexpr const char* get()
{ return "[Empty]"; }
};
struct foo
{
int m;
static constexpr int zero = 42;
};
int main()
{
std::cout << zero<int>::get() << "\n";
std::cout << zero<std::string>::get() << "\n";
std::cout << zero<foo>::get() << "\n";
}
Compact version w/o trait:
template<class T>
struct zero
{
private:
template<class X>
constexpr static decltype(X::zero) zero_impl(int)
{ return X::zero; }
template<class X>
constexpr static X zero_impl(short)
{ return X(); }
public:
constexpr static auto get()
-> decltype(zero_impl<T>(0))
{
return zero_impl<T>(0);
}
};
template<>
struct zero<std::string>
{
constexpr static const char* get()
{ return "[Empty]"; }
};
Maybe:
#include <iostream>
#include <vector>
template <typename T>
inline T zero() {
return T();
}
template <>
inline std::string zero<std::string>() {
return "[Empty]";
}
int main() {
std::vector<std::string> v(1, zero<std::string>());
std::cout << v[0] << '\n';
}
I have a half good news: I found a very simple way (leveraging SFINAE), however the output is not exactly what I expected :)
#include <iostream>
#include <string>
#include <vector>
// Meat
template <typename T, typename = decltype(T::Zero)>
auto zero_init_impl(int) -> T { return T::Zero; }
template <typename T>
auto zero_init_impl(...) -> T { return T{}; }
template <typename T>
auto zero_init() -> T { return zero_init_impl<T>(0); }
// Example
struct Special { static Special const Zero; std::string data; };
Special const Special::Zero = { "Empty" };
int main() {
std::vector<int> const v{3, zero_init<int>()};
std::vector<Special> const v2{3, zero_init<Special>()};
std::cout << v[0] << ", " << v[1] << ", " << v[2] << "\n";
std::cout << v2[0].data << ", " << v2[1].data << ", " << v2[2].data << "\n";
return 0;
}
As mentioned, the result is surprising was explained by dyp, we have to be careful not use std::initializer<int> by mistake and then read past the end:
3, 0, 0
Empty, Empty, Empty
Curly brace initialization yields a different result than regular brace initialization (see here) which gives the expected 0, 0, 0. So you have to use regular braces.