My naming skills are awful. Naming things is one of two hardest things in programming :)

Another point -

I have proof of concept LinkList implementation I made several years ago. Iterators there there looks like:

class LinkList{
   //...
   auto begin() const -> iterator{
      return head_;
   }

   constexpr static auto LinkList::end() -> iterator{
      return nullptr;
   }
}

Since end() does not require anything from the object (or class) it is marked static.

Now suppose some fancy programmer decides to do pointer to member function - begin() or end().
How is this possible with the standard library?

- begin() have 1 parameter - e.g. instance of the class (because it accesses private members, e.g. head_ )
- end() have 0 parameters.

With the current standard library there is no way this can be done except "do it yourself".



On Mon, May 25, 2020 at 5:42 PM Garrett May <garrett.ls.may@gmail.com> wrote:
That is fine - all of that makes sense.

However, I for one do not believe that such a class_invoke function is necessary to add to the standard library, in my opinion. It looks from my point of view to be required only in a specific situation where:
 - you need to call a member function pointer, because you require the (potentially private/protected) information inside the member; and
 - you need to call a function pointer, because you don't need any information from a member

From a stylistic perspective, class_invoke sounds like an odd name. It makes sense when you are calling a function pointer that resides inside a type, but:
- for a member function pointer, you aren't calling a function of a class - rather, a function of an instance of a class
- for a function pointer that doesn't reside inside a type, there is no class - so it is also odd for it to be called by class_invoke

And I think that highlights my point; function pointers and member function pointers are different types. Only in rare circumstances do I believe that the standard library should handle both generically - such as in std::invoke, which can handle other callable cases. This sounds more like a specific use case.

(N.B. Nikolay Mihaylov, duplicate reply due to lack of std-proposals in list of emailees)


On Mon, 25 May 2020 at 14:54, Nikolay Mihaylov <nmmm@nmmm.nu> wrote:
You are correct, this was my first implementation. I think "constexpr if" is not very readable and I usually prefer tag dispatch.

About the arguments - yes, those are different types, but suppose the class is passed from somewhere, here is my real code:

template<class PROTOCOL, class DB_ADAPTER, class CONNECTION>
class KeyValueWorkerProcessor{
// ... 
    template<typename F>
    WorkerStatus do_accumulate_(F func){
        const auto &p = protocol_.getParams();
        if (p.size() != 4)
            return err_BadRequest_();
        const auto &key    = p[1];
        uint16_t const count = from_string<uint16_t>(p[2]);
        const auto &prefix = p[3];
        protocol_.response_strings(buffer_, class_invoke(db_, func, key, count, prefix) );
        return WorkerStatus::WRITE;
    }
    auto do_getx(){
        return do_accumulate_(&DB_ADAPTER::getx);
    }
    auto do_count(){
        return do_accumulate_(&DB_ADAPTER::count);
    }
    auto do_sum(){
        return do_accumulate_(&DB_ADAPTER::sum);
    }
    auto do_min(){
        return do_accumulate_(&DB_ADAPTER::min);
    }
    auto do_max(){
        return do_accumulate_(&DB_ADAPTER::max);
    }
// ...
private:
    PROTOCOL    &protocol_;
    DB_ADAPTER    &db_;
    CONNECTION    &buffer_;
};

My first implementation had do_accumulate_() pasted 5 times - It was OK, but very long and code duplication.

Second implementation was with lambdas. It was rather confusing and hard to read.

Third implementation used direct code -  "(db_.*func)(key, count, prefix);", however I needed to remove "static" from my Mock adapter.
That was OK, but I thought - what if later I really need to call a static method. Then I will need to do it as "normal" method and hope the optimizer cleans up the code for me.

Current implementation works and looks very nice and clear, isn't it?

Nick


On Mon, May 25, 2020 at 3:37 PM Garrett May via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Are these not different types? One is a member function pointer, which requires two arguments - a Real* and an int - whereas the other is a function pointer which requires one argument - an int;

You can do the following:

template<typename C, typename F>
auto user(C &c, F func){
    if constexpr(std::is_member_function_pointer<F>::value){
        return (c.*func)(5);
    } else{
        return func(5);
    }
}

And subsequently call via:

user(real, &Real::inc);

user(real, Mock::inc);


On Mon, 25 May 2020, 1:16 pm Nikolay Mihaylov via Std-Proposals, <std-proposals@lists.isocpp.org> wrote:
Hello,

suppose you have following clases:

struct Mock{
static int inc(int){
return 0;
} static int dec(int){
return 0;
}
}; struct Real{
Real(int v) : v(v){} int inc(int a) const{
return a + v;
} int dec(int a) const{
return a - v;
} private:
int v;
}; template<typename C, typename F>
auto user(C &c, F func){
return (c.*func)(5);
}
This will allow to call:

user(real, &Real::inc);

but will not allow to do

user(real, &Mock::inc);

However because of generic context, both calls must be possible.

Here is simple implementation of the feature:

#include <type_traits>

namespace class_invoke_impl_{
    template <class T, class F, class... Args>
    constexpr auto class_invoke_(T &&cl, F func, std::true_type, Args&&... args){
        return (std::forward<T>(cl).*func)(std::forward<Args>(args)...);
    } 
 
    template <class T, class F, class... Args>
    constexpr auto class_invoke_(T const &, F func, std::false_type, Args&&... args){
        return func(std::forward<Args>(args)...);
    }
 
template <class T, class F, class... Args>
constexpr auto class_invoke(T &&cl, F func, Args&&... args){
    using namespace class_invoke_impl_;
    return class_invoke_(std::forward<T>(cl), func, std::is_member_pointer<F>{}, std::forward<Args>(args)...);
}


 
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals