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.
Related
I'd like to modernise a common technique I use or perhaps over use. It statically checks for method signatures and calls the methods if they exist. My approach predates C++17 by some time FWIW.
Currently, I used Boost's Type traits like BOOST_TTI_HAS_MEMBER_FUNCTION(event)
which allows something such as
template <typename M, typename E>
static inline typename std::enable_if<
has_member_function_event<current_t, void, boost::mpl::vector<M &, const E &>>::value
>::type
event(M &mux, S &g, const E &e) {
auto &node = boost::fusion::at<N>(g);
node.event(mux, e);
...
It works just fine but, you know, it's not the prettiest. Is there a way I might avoid the macros and join the rest of you in the modern world :-)?
Regards,
--Matt. (aka dinosaur)
Would simple, direct SFINAE suit your needs?
Here's a test function exercising various member functions, checking for adequate return types and const-correctness as well:
template <typename Obj> void exercise(Obj&& obj) {
if constexpr(has_bar(obj)) {
std::cout << "called T bar() -> something or void\n";
obj.bar();
}
if constexpr(converts<int>(has_foo(obj))) {
std::cout << "called int foo() const -> " << obj.foo() << "\n";
}
if constexpr(converts<long>(has_foo(obj, "some text"))) {
std::cout << "called long foo(std::string) -> " << obj.foo("some text") << "\n";
}
}
The has_bar implementation is simply:
template <typename T>
static constexpr auto has_bar(T&& obj) -> exists<decltype(obj.bar())> { return {}; }
template <typename... T>
static constexpr auto has_bar(T&&...) -> does_not_exist { return {}; }
To generically allow for checking signatures and avoid repetitious code, here's a helper macro (obviously optional):
#define DEF_HAS_MEMBER(name) \
template <typename T, typename... Args> \
static constexpr auto has_##name(T&& obj, Args&&... args) \
-> exists<decltype(std::forward<T>(obj).name(std::forward<Args>(args)...))> { return {}; } \
template <typename... T> \
static constexpr auto has_##name(T&&...) -> does_not_exist { return {}; }
DEF_HAS_MEMBER(foo)
DEF_HAS_MEMBER(bar)
The converts predicate now is an ultra-simple addition:
template <typename T, typename R>
static constexpr auto converts(R) { return std::is_convertible_v<typename R::return_type, T>; }
Everything together:
Live On Coliru
#include <string>
#include <type_traits>
#include <iostream>
template <typename R> struct exists : std::true_type { using return_type = R; };
struct does_not_exist : std::false_type { using return_type = void; };
#define DEF_HAS_MEMBER(name) \
template <typename T, typename... Args> \
static constexpr auto has_##name(T&& obj, Args&&... args) \
-> exists<decltype(std::forward<T>(obj).name(std::forward<Args>(args)...))> { return {}; } \
template <typename... T> \
static constexpr auto has_##name(T&&...) -> does_not_exist { return {}; }
DEF_HAS_MEMBER(foo)
DEF_HAS_MEMBER(bar)
struct Everything {
int foo(std::string /*unused*/) { return 42; }
int foo() const { return -1; }
void bar() {}
};
struct Some {
int foo() const { return -2; }
};
template <typename T, typename R>
static constexpr auto converts(R) { return std::is_convertible_v<typename R::return_type, T>; }
template <typename Obj> void exercise(Obj&& obj) {
std::cout << "===== " << __PRETTY_FUNCTION__ << "\n";
if constexpr(has_bar(obj)) {
std::cout << "called T bar() -> something or void\n";
obj.bar();
}
if constexpr(converts<int>(has_foo(obj))) {
std::cout << "called int foo() const -> " << obj.foo() << "\n";
}
if constexpr(converts<long>(has_foo(obj, "some text"))) {
std::cout << "called long foo(std::string) -> " << obj.foo("some text") << "\n";
}
}
int main() {
Everything e;
Everything const ce;
Some s;
Some const cs;
exercise(s);
exercise(cs);
exercise(ce);
exercise(e);
}
Prints
===== void exercise(Obj&&) [with Obj = Some&]
called int foo() const -> -2
===== void exercise(Obj&&) [with Obj = const Some&]
called int foo() const -> -2
===== void exercise(Obj&&) [with Obj = const Everything&]
called int foo() const -> -1
===== void exercise(Obj&&) [with Obj = Everything&]
called T bar() -> something or void
called int foo() const -> -1
called long foo(std::string) -> 42
OK. I have taken Alan Birtles advice and had a look at C++20 concepts for the solution.
Perhaps the use of std::addressof is overkill but it makes it almost a one-liner without a macro to define a HasMethodXYZ concept which may then be used for if constexpr or for easy SFINAE via a constraint. For example:
template <typename T>
concept HasMethodEvent = requires(T a, void (T::*m)(const std::string&) const) {
{&a == std::addressof(a)};
{m = &T::event};
};
struct dude_noway {};
struct dude_no {
void event(std::string& f) const {}
};
struct dude_yes {
void event(const std::string& f) const {}
};
template <typename T>
bool perhaps_event() {
if constexpr (HasMethodEvent<T>) {
return true;
} else {
return false;
}
}
template <HasMethodEvent T>
bool perhaps_event_sfinae() {
return true;
}
template <typename T>
bool perhaps_event_sfinae() {
return false;
}
//Catch2 test-case check
TEST_CASE("simple event check", "[check_method]") {
REQUIRE(perhaps_event<dude_yes>());
REQUIRE_FALSE(perhaps_event<dude_no>());
REQUIRE_FALSE(perhaps_event<dude_noway>());
REQUIRE(perhaps_event_sfinae<dude_yes>());
REQUIRE_FALSE(perhaps_event_sfinae<dude_no>());
REQUIRE_FALSE(perhaps_event_sfinae<dude_noway>());
}
which works OK with clang++-10 using libstdc++-10. For the win, I prefer this to the Boost TTI approach as it co-locates the method signature with the method name as part of the concept rather than using the MPL vector later and it feels simpler.
Thanks, --Matt.
I want to write a function that both input and output are variants.
VariantTypeA GetA(const VariantTypeB& b) {
return std::visit(MyVisitor(), b);
}
But I got a exception saying that
std::visit` requires the visitor to have a single return type.
How can I write a function like that? Can I use switch instead? How?
Use a visitor with return type VariantTypeA.
Using std::variant and letting the visitor deduce the element doesn't work if the variant has duplicate alternative types. Here's a function template variant_visit that preserves the index() of the variant. variant_visit also sets the corresponding alternative type in the result variant to std::monostate if the visitor returns void for some argument, because std::variant with void is ill-formed. SFINAE is omitted for simplicity.
namespace detail {
template <typename T>
using wrap_void_t = std::conditional_t<std::is_void_v<T>, std::monostate, T>;
template <typename Variant, typename Func,
typename = std::make_index_sequence<std::variant_size_v<
std::remove_reference_t<Variant>
>>>
struct result_variant;
template <typename Variant, typename Func, std::size_t... Is>
struct result_variant<Variant, Func, std::index_sequence<Is...>> {
using type = std::variant<
wrap_void_t<
std::invoke_result_t<
Func,
decltype(std::get<Is>(std::declval<Variant>()))
>
> ...
>;
};
template <typename Variant, typename Func>
using result_variant_t = typename result_variant<Variant, Func>::type;
template <typename Variant, typename Visitor, std::size_t... Is>
auto variant_visit(Variant&& variant, Visitor&& visitor, std::index_sequence<Is...>)
{
using Ret = result_variant_t<Variant, Visitor>;
using fp_t = Ret (*)(Variant&&, Visitor&&);
const fp_t fp_array[] = {
[](Variant&&, Visitor&&) -> Ret { throw std::bad_variant_access{}; },
[](Variant&& variant, Visitor&& visitor) -> Ret {
if constexpr (std::is_same_v<std::variant_alternative_t<Is, Ret>,
std::monostate>) {
std::invoke(std::forward<Visitor>(visitor),
std::get<Is>(std::forward<Variant>(variant)));
return Ret(std::in_place_index<Is>);
} else {
return Ret(
std::in_place_index<Is>,
std::invoke(std::forward<Visitor>(visitor),
std::get<Is>(std::forward<Variant>(variant)))
);
}
} ...
};
auto fp = fp_array[static_cast<std::size_t>(variant.index() + 1)];
return fp(std::forward<Variant>(variant), std::forward<Visitor>(visitor));
}
}
template <typename Variant, typename Visitor>
auto variant_visit(Variant&& variant, Visitor&& visitor)
{
return detail::variant_visit(
std::forward<Variant>(variant),
std::forward<Visitor>(visitor),
std::make_index_sequence<
std::variant_size_v<std::remove_reference_t<Variant>>
>{}
);
}
Usage example:
int main()
{
{
std::variant<int, int, double> var{std::in_place_index<1>, 10};
auto result = variant_visit(var, std::negate{});
std::cout << std::get<1>(result) << '\n';
}
{
std::variant<int, int, double> var{std::in_place_index<2>, 2e20};
auto result = variant_visit(var, std::negate{});
std::cout << std::get<2>(result) << '\n';
}
{
std::variant<std::unique_ptr<int>> var{std::make_unique<int>(30)};
auto result = variant_visit(var, [](auto& ptr) { return -*ptr; });
std::cout << std::get<0>(result) << '\n';
}
{
auto inspector = [](auto&& ptr) {
if constexpr (std::is_const_v<std::remove_reference_t<decltype(ptr)>>) {
std::cout << "const";
}
if constexpr (std::is_lvalue_reference_v<decltype(ptr)>) {
std::cout << "&\n";
} else {
std::cout << "&&\n";
}
};
std::variant<std::unique_ptr<int>> var{std::make_unique<int>(30)};
variant_visit(var, inspector);
variant_visit(std::as_const(var), inspector);
variant_visit(std::move(var), inspector);
}
}
Output:
-10
-2e+20
-30
&
const&
&&
(live demo)
You can do it by simply wrapping the visitor in a lambda that performs the conversion back to a variant:
template <class Visitor, class Variant>
auto variant_visit(Visitor &&visitor, Variant &&variant) {
return std::visit(
[&](auto &&in) -> std::remove_reference_t<Variant> {
return visitor(static_cast<decltype(in)>(in));
},
std::forward<Variant>(variant)
);
}
See it live on Wandbox
How to handle an api which returns different data types for the same input data types?
Looking at the below example, apicall should return a date or a string depending on the input attribute:
#include <iostream>
#include <string>
using namespace std;
???? apicall(string datatype, string attribute)
{
// code
}
int main(int argc, char** argv)
{
string datatype = "Thomas"
string attribute = "bithday"
cout << apicall(datatype, attribute) << endl;
string datatype = "Thomas"
string attribute = "address"
cout << apicall(datatype, attribute) << endl;
}
What could be in place of ???? (apicall return datatype) and how to handle these cases?
I am trying to understand these concepts as my experience to date has been with duck typed scripting languages.
The ideal solution is to use a std::variant, which is a safe union type like.
This allows you to write the following:
using DateOrString = std::variant<DateType, std::string>;
DateOrString api_call(std::string, std::string) {
// you can return both DateType and std::string
}
// ...
auto result = api_call("", "");
auto& str = std::get<std::string>(result);
Unfortunately std::variant is a C++17 feature. However different compilers already support it.
As already has been suggested, boost has a variant class and you can use it with any C++ standard.
As last option, you may implement a "variant-like" class which handles both a date and a string. Your function should return it.
Here a demo how to quickly implement that kind of class.
Note that that class is safe because the type is checked at runtime.
As a variant object, your callee function should branch on the type, something like:
auto result = api_call(/*...*/);
if (result.is_string()) {
// result is a string
const auto& str = result.get_string();
} else {
// result is a date
const auto& date = result.get_date();
}
... returns different data types for the same input data types?
This is literally impossible. A function is defined with one (or zero) return types, and zero or more input parameter types.
The workarounds are:
Write a single function returning a variant type, such as std::variant in C++17, or Boost.Variant if that's not available.
Write multiple functions with different return types (the caller just has to choose the right one)
Invert control, so that instead of returning a value, you pass an object capable of processing all the required types:
struct APIHandler {
virtual ~APIHandler() {}
virtual void operator()(int) {}
virtual void operator()(string) {}
};
void apicall(string name, string attr, APIHandler &h) {
// dummy implementation
if (attr == "address") {
h("123 Woodford Road");
} else if (attr == "birthday") {
h(19830214);
}
}
// implement your type-specific logic here
struct MyHandler: APIHandler {
void operator()(int i) override {
cout << "got an int:" << i << '\n';
}
void operator()(string s) override {
cout << "got a string:" << s << '\n';
}
};
// and use it like:
MyHandler mh;
apicall("Thomas", "birthday", mh);
apicall("Thomas", "address", mh);
You want a std::variant in C++17 or a boost::variant or roll your own crude variant something like this:
constexpr std::size_t max() { return 0; }
template<class...Ts>
constexpr std::size_t max( std::size_t t0, Ts...ts ) {
return (t0<max(ts...))?max(ts...):t0;
}
template<class T0, class...Ts>
struct index_of_in;
template<class T0, class...Ts>
struct index_of_in<T0, T0, Ts...>:std::integral_constant<std::size_t, 0> {};
template<class T0, class T1, class...Ts>
struct index_of_in<T0, T1, Ts...>:
std::integral_constant<std::size_t,
index_of_in<T0, Ts...>::value+1
>
{};
struct variant_vtable {
void(*dtor)(void*) = 0;
void(*copy)(void*, void const*) = 0;
void(*move)(void*, void*) = 0;
};
template<class T>
void populate_vtable( variant_vtable* vtable ) {
vtable->dtor = [](void* ptr){ static_cast<T*>(ptr)->~T(); };
vtable->copy = [](void* dest, void const* src){
::new(dest) T(*static_cast<T const*>(src));
};
vtable->move = [](void* dest, void* src){
::new(dest) T(std::move(*static_cast<T*>(src)));
};
}
template<class T>
variant_vtable make_vtable() {
variant_vtable r;
populate_vtable<T>(&r);
return r;
}
template<class T>
variant_vtable const* get_vtable() {
static const variant_vtable table = make_vtable<T>();
return &table;
}
template<class T0, class...Ts>
struct my_variant {
std::size_t index = -1;
variant_vtable const* vtable = 0;
static constexpr auto data_size = max(sizeof(T0),sizeof(Ts)...);
static constexpr auto data_align = max(alignof(T0),alignof(Ts)...);
template<class T>
static constexpr std::size_t index_of() {
return index_of_in<T, T0, Ts...>::value;
}
typename std::aligned_storage< data_size, data_align >::type data;
template<class T>
T* get() {
if (index_of<T>() == index)
return static_cast<T*>((void*)&data);
else
return nullptr;
}
template<class T>
T const* get() const {
return const_cast<my_variant*>(this)->get<T>();
}
template<class F, class R>
using applicator = R(*)(F&&, my_variant*);
template<class T, class F, class R>
static applicator<F, R> get_applicator() {
return [](F&& f, my_variant* ptr)->R {
return std::forward<F>(f)( *ptr->get<T>() );
};
}
template<class F, class R=typename std::result_of<F(T0&)>::type>
R visit( F&& f ) & {
if (index == (std::size_t)-1) throw std::invalid_argument("variant");
static const applicator<F, R> table[] = {
get_applicator<T0, F, R>(),
get_applicator<Ts, F, R>()...
};
return table[index]( std::forward<F>(f), this );
}
template<class F,
class R=typename std::result_of<F(T0 const&)>::type
>
R visit( F&& f ) const& {
return const_cast<my_variant*>(this)->visit(
[&f](auto const& v)->R
{
return std::forward<F>(f)(v);
}
);
}
template<class F,
class R=typename std::result_of<F(T0&&)>::type
>
R visit( F&& f ) && {
return visit( [&f](auto& v)->R {
return std::forward<F>(f)(std::move(v));
} );
}
explicit operator bool() const { return vtable; }
template<class T, class...Args>
void emplace( Args&&...args ) {
clear();
::new( (void*)&data ) T(std::forward<Args>(args)...);
index = index_of<T>();
vtable = get_vtable<T>();
}
void clear() {
if (!vtable) return;
vtable->dtor( &data );
index = -1;
vtable = nullptr;
}
~my_variant() { clear(); }
my_variant() {}
void copy_from( my_variant const& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->copy( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
void move_from( my_variant&& o ) {
if (this == &o) return;
clear();
if (!o.vtable) return;
o.vtable->move( &data, &o.data );
vtable = o.vtable;
index = o.index;
}
my_variant( my_variant const& o ) {
copy_from(o);
}
my_variant( my_variant && o ) {
move_from(std::move(o));
}
my_variant& operator=(my_variant const& o) {
copy_from(o);
return *this;
}
my_variant& operator=(my_variant&& o) {
move_from(std::move(o));
return *this;
}
template<class T,
typename std::enable_if<!std::is_same<typename std::decay<T>::type, my_variant>{}, int>::type =0
>
my_variant( T&& t ) {
emplace<typename std::decay<T>::type>(std::forward<T>(t));
}
};
then your code looks like:
variant<string, int> apicall(string datatype, string attribute)
{
if (datatype > attribute) return string("hello world");
return 7;
}
int main()
{
string datatype = "Thomas"
string attribute = "bithday"
apicall(datatype, attribute).visit([](auto&&r){
cout << r << endl;
});
string datatype = "Thomas"
string attribute = "address"
apicall(datatype, attribute).visit([](auto&& r){
cout << r << endl;
});
}
with whatever visit or apply_visitor free function or method your particular variant supports.
This gets much more annoying in C++11 as we don't have generic lambdas.
You could use a variant, but it's up to the caller site to check the results. Boost and std defines two variant types, i.e. std::variant and std::any.
I am trying to write code to do something similar (code written for demonstration purposes) to this:
template <typename F, typename Args...>
inline auto runFunc(F func) -> foo
{
return foo([func](Args... args) -> std::result_of<F>::type
{
// Do something before calling func
func(args...);
// Do something after call func
});
}
So basically I am trying to write a function that returns an object that takes lambda that matches the templated function type. Obviously this code won't work because I do not have Args... defined. How would I solve this in C++11?
template<class F_before, class F, class F_after>
struct decorate_func_t {
F_before f0;
F f1;
F_after f2;
template<class...Args>
typename std::result_of<F(Args...)>::type operator()(Args&&...args)const{
f0();
auto r = f1(std::forward<Args>(args)...);
f2();
return r;
}
};
template<class F_before, class F, class F_after>
decorate_func_t<F_before, F, F_after>
decorate_func( F_before before, F f, F_after after ){
return {std::move(before), std::move(f), std::move(after)};
}
Then:
template <typename F, typename Args...>
inline auto runFunc(F func) -> foo
{
return foo(decorate_func(
[]{/* Do something before calling func */},
func,
[]{/* Do something after call func */ }
};
}
the lack of auto parameters in C++11 lambdas makes this about the best you can do.
In C++14 this is trivial:
template <class F>
auto runFunc(F func)
{
return foo(
[func](auto&&... args) // ->decltype(auto) maybe
{
// Do something before calling func
auto r = func(decltype(args)(args)...);
// Do something after call func
return r;
}
);
}
note that many nominally C++11 compilers actually support auto parameters on lambdas.
You can use a support structure as in the following example:
#include<type_traits>
#include<cassert>
struct foo {
template<typename F>
foo(F f) { assert(42 == f(42)); }
};
template<typename>
struct S;
template<typename R, typename... Args>
struct S<R(*)(Args...)> {
template <typename F>
static auto runFunc(F func) -> foo
{
return foo{[func](Args... args) -> R
{
// Do something before calling func
auto r = func(args...);
// Do something after call func
return r;
}};
}
};
template<typename F>
inline auto runFunc(F func) -> foo
{
return S<F>::runFunc(func);
}
int f(int i) { return i; }
int main() {
runFunc(f);
}
For it's not clear to me what's the context of the problem, I'm not sure I got exactly what you were asking for.
I hope the code above can help you.
Still being unsure it this is what you're searching for, I risk posting:
#include <iostream>
struct foo
{
template<typename T>
foo(T lambda)
{
lambda(1, 2);
}
};
template <typename F, typename... Args>
inline typename std::result_of<F>::type runFunc(F func)
{
return foo(
[func](Args... args)
{
std::cout << "Before";
func(args...);
std::cout << "After";
}
);
}
struct print
{
void operator()(int i) const
{
std::cout << i << std::endl;
}
void operator()(int i, int j) const
{
std::cout << i << " " << j << std::endl;
}
};
int main()
{
runFunc<print, int, int>(print());
}
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