0

I was experimenting with finding a type & then assigning the method, such as:

decltype(std::addressof(&std::vector<int>::push_back<int&&>)) x =
&std::vector<int>::push_back;

I was stuck at following error:

error: expected primary-expression before ‘decltype

Above code is only as a minimal example. In reality, the address of the method will be passed to a template class along with its type. i.e. it can be &std::set<T>::insert<T&&> as well. Hence auto may NOT be an option.
See the pseudo code:

template<typename Type, // <-- int, float
         template<typename...> class Container, // <-- std::vector, std::set
         typename Method_t,  // <-- decltype(push_back(T&&), insert(T&&))
         Method_t Method>  // <-- push_back(T&&), insert(T&&)
struct Wrap { ... };

#define WRAP(TYPE, CONTAINER, METHOD) \
  Wrap<TYPE, CONTAINER, decltype(&CONTAINER<TYPE>::METHOD<TYPE&&>), &CONTAINER<TYPE>::METHOD>

Usage:

WRAP(int, std::vector, push_back); // uses `push_back(int&&)`
WRAP(float, std::set, insert);  // uses `insert(float&&)`

What is the correct way to deduce the address of a template class's overloaded member method?

In my case, Method_t is supposed to be any among the push_back, insert, push_front, push with the T&& overload versions only.
This Qn didn't help: Address of templated member function

Community
  • 1
  • 1
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • Every now and then a proposal pops up to allow programmatic enumeration of overload sets in some form or other, but nothing has matured yet into anything serious. – Kerrek SB Jan 08 '17 at 04:43

2 Answers2

0

First off, std::addressof takes the address of objects, not of members (in the sense of pointers-to-member).

Second, std::vector<int>::push_back is not a template.

Third, to control overload resolution when taking the address of a function, use the cast notation:

static_cast<void (std::vector<int>::*)(int&&)>(&std::vector<int>::push_back)
//          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
//          overload                            name of overload set
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • `auto` is not a option here. Not particular about `addressof`, it's just a hint. Because its documentation says: *"@brief Returns the actual address of the object or function referenced by r, even in the presence of an overloaded operator&."* I have updated my Qn with some more details on the use case. Getting the simple address is fine, but I want to deduce the address (e.g. using `decltype` or any such facility). For example, the addresses of `vector::push_back` and `set::insert` don't match, except that they both take `T&&` argument. How to do that? – iammilind Jan 08 '17 at 04:31
  • @iammilind: Hm, interesting. I'm looking at libc++'s implementation when `addressof` was still in library, and that doesn't work for functions. I wonder if this changed in C++17 (where `addressof` has become constexpr and thus magic). I don't think you're allowed to reinterpret-cast a function to a char lvalue. – Kerrek SB Jan 08 '17 at 04:36
  • @iammilind: Regardless, you cannot say `addressof(C::mem)` for class members, since the only way to use class member names like this is as part of a unary `&`-expression `&C::mem` (which cannot be overloaded). – Kerrek SB Jan 08 '17 at 04:40
  • 3
    Fourth, you are not allowed to take the address of standard library member functions. – T.C. Jan 08 '17 at 04:51
  • Is there any way to capture address of an overloaded method, Without specifying its type explicitly? @T.C. can you shed more light on why addresses of `std` methods are not allowed, possibly with some reference. Is it a UB, (amusing)? – iammilind Jan 08 '17 at 05:33
  • I have posted a workaround solution with little tweaking.@T.C., do you think that the passage you posted, really restricts us Not to use the address of a template member method? Still not sure. Suppose if we still use it, then will it ever result in UB. I feel that the compiler may generate an error if it has changed some of the signatures. – iammilind Jan 08 '17 at 11:30
  • 4
    @iammilind A slight tweak of T.C.'s comment, then: there's no *useful* way to take the address of most standard library member functions. You *might* be able to do it in a strictly conforming program with SFINAE in a situation where the code that takes the address has the same effect as the code that doesn't take the address. But that still requires you to write the code that handles the case where taking the address fails, so doesn't get you anything. You're right that if you unconditionally attempt to use it, and the implementation uses different signatures, you would get an error. –  Jan 08 '17 at 11:44
  • 3
    @hvd Additionally, the library is designed on the assumption that it won't get a pointer-to-standard-library-member-function. That's why the pointer-to-member case of `INVOKE` unconditionally unwraps `std::reference_wrapper`s and doesn't bother considering the possibility that someone is invoking a member function of `std::reference_wrapper`. – T.C. Jan 08 '17 at 16:04
0

As of today, it's not possible to automatically deduce the overloaded functions per se. One needs to specify its complete signature in the left side for the compiler to be able to deduce the appropriate type.
Example: for following 2 functions:

void C::foo (int);
void C::foo (double);

One must mention the complete prototype on the LHS,

void (C::*method)(int) = &C::foo;  // OK

But unfortunately we can't do something like,

auto method = &C::foo(int);  // not allowed

Hence, whatever is asked in the Qn is Not possible to achieve in its current form.


But if the requirement is little tweaked, then one can deduce the return type and still achieve the final desired results.
Here is a little changed syntax for struct Wrap:

template<typename Type,
         template<typename...> class Container,
         typename Return,  // <--- changed
         Return (Container<Type>::*Method)(Type&&)>  // <--- full definition
struct Wrap { ... }

With above changed code, instead of deducing the type of whole method, we just need to deduce the "return type". The argument is already known to be Type&& as already specified in the Qn. Now the WRAP macro looks like this:

#define WRAP(TYPE, CONTAINER, METHOD) \
  Wrap<TYPE, CONTAINER, decltype(((CONTAINER<TYPE>*)nullptr)->METHOD(TYPE())), &CONTAINER<TYPE>::METHOD>

Usage:

WRAP(int, std::vector, push_back) wrap;

Application Demo.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • as I understand (I might be wrong) quoted by T.C. part of the standard - you cannot be sure if the member function has exactly the same signature as declared in standard - the signature might contain additional parameters with defaulted values - the only requirement is that it **must** match when passing parameters that are described in signatures declared in standard... In this case (if I interpreted the quote correctly) `static_cast` won't be any helpful... – W.F. Jan 08 '17 at 12:47