invoke_result with member (operator[]) function
Asked Answered
P

3

6

How do I call invoke_result correctly for a member function? Or specifically for an operator member function. I tried std::invoke_result<T::operator[], size_type> to no success. What would be the correct syntax in this case?

Pet answered 6/7, 2019 at 0:31 Comment(4)
@TedLyngmo I simply thought my code would be misleading, since it would just detract from the main question. T here is a template typename anyways, so it should work in general for any class providing an operator[] with one argument of size_t.Pet
I think you underestimate people willing to help. :-) Your code will extremely seldom be mislleading!Overgrow
@TedLyngmo I don't doubt people's willingness to help, I just know I probably wouldn't do a good job of providing a non-misleading minimal example. I've been there, I have done that. It usually turns out bad, because I have irrelevant details in my code which mislead the people trying to answer, so I try my best to provide only the minimal necessary details as of late.Pet
@ightxbulb - Ok, let's hope your future at SO will be nice. I get my wrist slapped every now and then - and I've got 40 years in the business. It's not an easy game - but it's worth every minute!Overgrow
A
7

Don't. Use decltype(std::declval<T&>()[size_type{}]) or something similar (adjust the value category and the cv-qualification as needed).

invoke_result is for when you have an invocable/callable object. You don't have one, so don't try to hammer square pegs into round holes.

Acicular answered 6/7, 2019 at 1:0 Comment(3)
This works. I assume it doesn't construct T by calling declval though, does it? Since T in this case is quite large.Pet
@Pet decltype takes an unevaluated operand. So no, it constructs nothing at runtime.Acicular
Does this imply that it constructs it at compile time though (possibly increasing compilation time if there are multiple compile time invocations of this)?Pet
D
6

What about as follows ?

std::invoke_result<decltype(&T::operator[]), T, size_type>

But this syntax should works with a single, and not template, operator[].

In case of template or overload, you should avoid std::invoke_result and follows the decltype() way suggested by T.C.

Or, maybe, you can wrap the call in a lambda function and apply std::invoke_result to the lambda (if you really, really want to use std::invoke_result).

Regarding the std::invoke_result syntax, take in count that a pointer to a member function is a completely different things, compared to a pointer to a regular function. Anyway, you can roughly see it as a pointer to a regular function receiving an additional argument (in first position) corresponding to the object that call its method.

So, in your example, the first T argument represent the object of type T that call its operator.

Donell answered 6/7, 2019 at 0:51 Comment(11)
I get a cannot determine which instance of overloaded function ... is intended.Pet
@Pet - I suppose you have more operator[] (const and not-const version?) in your class.Donell
@lightxbulb: Perhaps you should update your question with a minimal reproducible example then.Disqualify
@Donell There's a const and non-const version of it, yes. No other overload. Is this what's causing the issue?Pet
@Pet - yes, I suppose is it. As said: "this syntax should works with a single, and not template, operator[]". To verify, try commenting the non-const version to see if the error disappear.Donell
@Donell Yes, this seems to have been a problem, while I couldn't comment out any of the operators since this was breaking the whole code, I tested it by defining a new operator and it turned out it's specifically the const overload causing the issue. T.C.'s answer seems indeed a more adequate solution to what I am trying to do.Pet
@Pet - I'm agree. I've tried to explain the syntax for std::invoke_result and member functions but I think it's a bad idea to use it to detect the returned type of a specific method. The T.C. solution is, IMHO, a better solution because works also in case of overloading and template methods.Donell
@Pet - Anyway, isn't exactly "the const overload causing the issue". There is nothing wrong with the const version. The issue is caused by the presence of more than one operator[], so the compiler doesn't know which one choose when you write decltype(&T::operator[]).Donell
@Donell Is there a specific syntax to invoke specifically the const version in this case? I tried swapping T with const T to see if it will work, but this didn't produce results. How does one go about resolving such ambiguities? I would assume that one can differentiate between the different overloads through the argument types given, however what can I do for the const vs non-const case. (I am asking out of curiosity - I do not plan to use this rather than T.C.'s version, but I assume there are cases where invoke_result is a valid solution).Pet
@Pet - sorry but... if there is a specific syntax, I don't know it. But with T.C. solution, you can add const to the std::declval() type: decltype(std::declval<T const &>()[size_type{}])Donell
@Donell T.C.'s solution works either way. I was just curious what the correct syntax for resolving the ambiguity would have been for the invoke_result version. It's not tragic though.Pet
A
0
// Tank you! Thanks to your hint, I got the following 
code:
struct C_STRUCT { 
    double Func(char, int&) { return 3.14; }; 
};
std::invoke_result<decltype(&C_STRUCT::Func), C_STRUCT, 
char, int&>::type   dbl_var_g = 3.14;
static_assert(std::is_same<decltype(dbl_var_g), 
double>::value, "Несоответствие типов");
Allopathy answered 6/3 at 10:33 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewCanicular

© 2022 - 2024 — McMap. All rights reserved.