Date: Thu, 22 Sep 2022 16:45:26 +0100
On Wed, Sep 21, 2022 at 7:13 PM Breno GuimarĂ£es via Std-Proposals
<std-proposals_at_[hidden]> wrote:
> Such that:
>
> v->Init();
>
> would be transformed by the compiler into
>
> v.operator->( [&] (auto& arg) { arg.Init(); } );
>
> By doing so, all you need is the ability to pass more arguments to the operator-> (today it's forbidden).
> See how that would work for variant: https://godbolt.org/z/xxKnE44dr
Breno I found your code up on GodBolt very helpful, thank you. I'm
made some changes to it:
https://godbolt.org/z/KaMdv1fqn
And also here it is copy-pasted:
#include <variant> // We're adding functionality to std::variant
#include <cstddef> // size_t
#include <tuple> // tuple, tuple_size_v, std::get<>()
#include <functional> // invoke
#include <utility> // forward, index_sequence, make_index_sequence
#include <type_traits> // remove_reference_t
namespace detail {
// The standard library has a function called 'apply'
// but I need to make a new function called 'apply_with_pointer'
// which has an extra parameter. So instead of invoking as follows:
// std::apply(func, my_tuple);
// , we instead invoke like this:
// apply_with_pointer(func, some_pointer, my_tuple);
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_with_pointer_impl(F &&f, void *const p,
Tuple &&t, std::index_sequence<I...>)
{
return std::invoke(std::forward<F>(f), p,
std::get<I>(std::forward<Tuple>(t))...);
}
template <class F, class Tuple>
constexpr decltype(auto) apply_with_pointer(F &&f, void *const p, Tuple &&t)
{
return apply_with_pointer_impl(
std::forward<F>(f), p, std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}
} // close namespace 'detail'
struct A {
int init(int const arg) { return arg + 7; }
};
struct B {
int init(int const arg) { return arg - 3; }
};
template<typename... Types>
struct NewStdVariant : public std::variant<Types...> {
typedef std::variant<Types...> V;
using V::V;
template<class Visitor>
auto operator_arrow(Visitor &&visitor)
{
return std::visit(visitor, *static_cast<V*>(this) );
}
};
template<typename R, typename... Args>
struct HelperForArrowOperator {
std::tuple<Args...> stored_args;
HelperForArrowOperator(Args... args) : stored_args(args...) {}
template<class T>
static R invoke(void *const arg_p, Args... args)
{
return static_cast<T*>(arg_p)->init( args... );
}
template<class T>
R operator()(T &obj)
{
return detail::apply_with_pointer(invoke<T>, &obj, stored_args);
}
};
#include <iostream>
template<typename... Types>
void foo(NewStdVariant<Types...> &v)
{
// The following line:
//
// std::cout << v->init(5) << std::endl;
//
// gets translated into:
HelperForArrowOperator<
/* return type */ int,
/* 1st parameter type */ int> monkey( /* 1st argument */ 5);
std::cout << v.operator_arrow(monkey) << std::endl;
}
int main(void)
{
NewStdVariant<A,B> obj;
foo(obj);
obj.emplace<B>();
foo(obj);
}
<std-proposals_at_[hidden]> wrote:
> Such that:
>
> v->Init();
>
> would be transformed by the compiler into
>
> v.operator->( [&] (auto& arg) { arg.Init(); } );
>
> By doing so, all you need is the ability to pass more arguments to the operator-> (today it's forbidden).
> See how that would work for variant: https://godbolt.org/z/xxKnE44dr
Breno I found your code up on GodBolt very helpful, thank you. I'm
made some changes to it:
https://godbolt.org/z/KaMdv1fqn
And also here it is copy-pasted:
#include <variant> // We're adding functionality to std::variant
#include <cstddef> // size_t
#include <tuple> // tuple, tuple_size_v, std::get<>()
#include <functional> // invoke
#include <utility> // forward, index_sequence, make_index_sequence
#include <type_traits> // remove_reference_t
namespace detail {
// The standard library has a function called 'apply'
// but I need to make a new function called 'apply_with_pointer'
// which has an extra parameter. So instead of invoking as follows:
// std::apply(func, my_tuple);
// , we instead invoke like this:
// apply_with_pointer(func, some_pointer, my_tuple);
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_with_pointer_impl(F &&f, void *const p,
Tuple &&t, std::index_sequence<I...>)
{
return std::invoke(std::forward<F>(f), p,
std::get<I>(std::forward<Tuple>(t))...);
}
template <class F, class Tuple>
constexpr decltype(auto) apply_with_pointer(F &&f, void *const p, Tuple &&t)
{
return apply_with_pointer_impl(
std::forward<F>(f), p, std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}
} // close namespace 'detail'
struct A {
int init(int const arg) { return arg + 7; }
};
struct B {
int init(int const arg) { return arg - 3; }
};
template<typename... Types>
struct NewStdVariant : public std::variant<Types...> {
typedef std::variant<Types...> V;
using V::V;
template<class Visitor>
auto operator_arrow(Visitor &&visitor)
{
return std::visit(visitor, *static_cast<V*>(this) );
}
};
template<typename R, typename... Args>
struct HelperForArrowOperator {
std::tuple<Args...> stored_args;
HelperForArrowOperator(Args... args) : stored_args(args...) {}
template<class T>
static R invoke(void *const arg_p, Args... args)
{
return static_cast<T*>(arg_p)->init( args... );
}
template<class T>
R operator()(T &obj)
{
return detail::apply_with_pointer(invoke<T>, &obj, stored_args);
}
};
#include <iostream>
template<typename... Types>
void foo(NewStdVariant<Types...> &v)
{
// The following line:
//
// std::cout << v->init(5) << std::endl;
//
// gets translated into:
HelperForArrowOperator<
/* return type */ int,
/* 1st parameter type */ int> monkey( /* 1st argument */ 5);
std::cout << v.operator_arrow(monkey) << std::endl;
}
int main(void)
{
NewStdVariant<A,B> obj;
foo(obj);
obj.emplace<B>();
foo(obj);
}
Received on 2022-09-22 15:45:38