Who Wants to Take a Crack at Some Metaprogramming Bullshit?

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
User avatar
chili
Site Admin
Posts: 3909
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by chili » November 25th, 2019, 12:24 am

So I've been tinkering with a simple idea of a metafunction that can take a normal binary function like std::less that works with references, and adapt it to work with pointers. A simple implementation here that works for std::unique_ptr (the most common use case for me personally), but the return value is fixed to bool: https://wandbox.org/permlink/JwNdoVcMom26HeGE. I suppose it's not too hard to make that work by adapting the return value to whatever the return value of the base functor is. A little more work might be required to support other pointer types (shared_ptr<T>, T*), probably some template specialization elbow grease I guess. But what really piqued my interest was the ability to make an adaptor that didn't just resolve T* to T&, but one that could resolve T* to T::SomeInstanceFunction() or T::SomeMemberVariable. An implementation of that for pointer-to-data-member is here: https://wandbox.org/permlink/mKxXWkr6R2R1nL1C.

Works pretty well, but the syntax annoys me. What I would like, is I would like Crapdaptor<std::less,&Finkle::y>{}. I feel like this could be possible, perhaps with some usage of auto template parameters (cybo also expressed a similar opinion). So if any brave souls want to venture an attempt into the harsh lands of template BS, I'd be interested in seeing what an implementation of that would look like :D. Alternatively (or in addition), making the return value of the adaptor operator() reactive or supporting other pointer types might be cool beans.
Chili

User avatar
krautersuppe
Posts: 80
Joined: September 14th, 2015, 10:58 pm
Location: Istanbul

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by krautersuppe » November 25th, 2019, 7:31 pm

*cough* cyber *cough*
Kraut

albinopapa
Posts: 4016
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by albinopapa » November 28th, 2019, 3:32 am

So let me get some clarification:

Crapdaptor<std::less,&Finkle::y>{}

This is going to be a functor that takes as params a binary function and a pointer to member/member function, and Crapdaptor::operator() is suppose to take any pointer or pointer-like type and forward as reference to the binary functor?
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3909
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by chili » November 30th, 2019, 3:51 am

Yeah, that is the idea. Although I suppose you could use SFINAE to make the adaptor support both binary and unary. You can just do normal overloading to support operator() for shared_ptr, unique_ptr, T*.

If the second template param is a data member ptr, forward reference to that member of the object pointed to, if template param is a unary member function ptr, forward reference to the result value of the member function called on the object pointed to, and if the template param is a type, dereference the object pointed to and forward reference to that object.
Chili

albinopapa
Posts: 4016
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by albinopapa » November 30th, 2019, 11:10 pm

Although I suppose you could use SFINAE to make the adaptor support both binary and unary
The adapter operator() could probably just be a variadic template, though that brings up other complexities.

As for the choosing what to do with the type the second parameter ( S ) is and what to forward to the comparator in this case, I believe std::invoke is what you want to use.

As to what you want to use for syntax, I'm not sure there is a way around specifying more than a function like object and a pointer to member/member function.

Code: Select all

template<template<typename> class F, class T, class R, R T::*ptr>
struct TestAdapter
{
	template<typename...Args>
	bool operator()( const std::unique_ptr<T>& pl, Args&&...args ) const
	{
		return F<R>{}( std::invoke( ptr, pl ), std::invoke( ptr, std::forward<Args>( args )... ) );
	}
};
If it wasn't for the "R T::*ptr" portion, the T could be moved down to the operator() template parameter and have the compiler deduce the T.

If you are passing pointer or pointer like types, then you wouldn't necessarily need overloads for each type as they each dereference the same way and with invoke it seems to handle pointer types just fine.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
cyboryxmen
Posts: 181
Joined: November 14th, 2014, 2:03 am

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by cyboryxmen » December 1st, 2019, 1:20 am

For a moment there, I thought you were actually going to give me a challenge.

Code: Select all

template<typename Function>
constexpr auto Crapdaptor = [](auto&& pl, auto&& pr)
{
	return Function{}(*pl,*pr);
};

Code: Select all

std::sort(v.begin(),v.end(),Crapdaptor<std::greater<Foo>>);
Zekilk

User avatar
cyboryxmen
Posts: 181
Joined: November 14th, 2014, 2:03 am

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by cyboryxmen » December 1st, 2019, 7:16 am

Additionally, you can do

Code: Select all

constexpr auto Crapdaptor = [](auto&& function)
{
	return [function](auto&& left_ptr, auto&& right_ptr)
	{
		return function(*left_ptr, *right_ptr);
	};
};

Code: Select all

std::sort(v.begin(),v.end(),Crapdaptor(std::mem_fn(&Foo::operator>)));
Zekilk

albinopapa
Posts: 4016
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by albinopapa » December 1st, 2019, 7:35 am

Can you post some working code in online compiler? I can't seem to get your version to work with his examples.

I think he's trying to avoid declaring/defining operator> and operator< overloads for user defined types.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
chili
Site Admin
Posts: 3909
Joined: December 31st, 2011, 4:53 pm
Location: Japan
Contact:

Re: Who Wants to Take a Crack at Some Metaprogramming Bullshit?

Post by chili » December 1st, 2019, 2:47 pm

cyboryxmen wrote:
December 1st, 2019, 7:16 am
Additionally, you can do

Code: Select all

constexpr auto Crapdaptor = [](auto&& function)
{
	return [function](auto&& left_ptr, auto&& right_ptr)
	{
		return function(*left_ptr, *right_ptr);
	};
};

Code: Select all

std::sort(v.begin(),v.end(),Crapdaptor(std::mem_fn(&Foo::operator>)));
Pls don't :peppers:
albinopapa wrote:
December 1st, 2019, 7:35 am
I think he's trying to avoid declaring/defining operator> and operator< overloads for user defined types.
The point wasn't really to avoid defining operators. It's just that we have these nice functions like std::less/std::greater that work with containers of objects, but not containers of pointer types (which is often what you're dealing with). Then as an extension of that concept, I got the idea of using member pointers make the idea even more flexible (e.g. accumulating by std::multiplies across the return value of some member function on a container of pointer types).
Chili

Post Reply