7

I have a class which uses return code:

class MyClass
{
    // ...

public:
    // ValueType get_value() const;               // usual code
    ErrorCode get_value(ValueType& value) const;  // uses error code

   // ...
};

Thus, the second form of get_value() actually provides the value as function parameter, rather than as return value.

Is it possible to deduce the type of the function parameter of get_value(), maybe using decltype?

int main()
{
    // ...

    MyClass my_class;
    // auto val = my_class.get_value();  // okay: value has correct type

    declytype( /* something here */ ) value;
    const auto error = my_class.get_value( value );

    // ...
}
Walter
  • 44,150
  • 20
  • 113
  • 196
nyarlathotep108
  • 5,275
  • 2
  • 26
  • 64
  • 2
    Your question is confusing me. "This means that the parameter is actually the return value of the `get_value` function." So you mean `ValueType` and `ErrorCode` are the same type? `MyClass` doesn't have an `operator()`, you can't call it. Are you asking how to deduce the type of the first parameter of a function? – Rakete1111 Jul 06 '17 at 14:36
  • @Rakete1111 no, it means that if it was not for the ErrorCode, ValueType would have been the function return type – nyarlathotep108 Jul 06 '17 at 14:38
  • 1
    Did you mean to call my_class.get_value(value), or is my_class supposed to be a callable object? – ivme Jul 06 '17 at 14:47
  • @Chad wrong typing. I edited the question. Sorry guys, I hope now it is clear – nyarlathotep108 Jul 06 '17 at 14:49
  • Duplicate of https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda? – François Andrieux Jul 06 '17 at 14:57
  • Is your goal this? If supplying an argument of type `ValueType` to the `get_value` function produces an error, return an error code. Otherwise return a `ValueType`. – ivme Jul 06 '17 at 15:00
  • Now that you have two functions with the same name, to tell them apart you need to know its return and argument types. – Maxim Egorushkin Jul 06 '17 at 15:19
  • @MaximEgorushkin The return type is never part of the function name. You only need the argument types. I added the second `get_value()` to highlight the issue and the reason for not using that much simpler version. – Walter Jul 06 '17 at 15:21
  • Don't use this syntax, it's C-style error treatment. In C++, you throw an exception in case of an error and let the caller catch and handle it. – Walter Jul 06 '17 at 15:24
  • @Walter You confuse function signature with function name. Overlooking that, I do not see how your comment is relevant. Try taking a pointer to an overloaded function without specifying its return type. – Maxim Egorushkin Jul 06 '17 at 15:25
  • @Walter Your statement with regards to the return type is at least inaccurate: https://stackoverflow.com/a/290048/412080 – Maxim Egorushkin Jul 06 '17 at 15:33
  • 1
    @Walter "added the second get_value()" - so my answer is broken :) – Edgar Rokjān Jul 06 '17 at 15:33
  • @EdgarRokyan your answer was actually to the requested question :) – nyarlathotep108 Jul 06 '17 at 15:52
  • @nyarlathotep108 so you'd probably better to revert the last edit not to confuse people in the future... – Edgar Rokjān Jul 06 '17 at 16:26
  • Sorry guys, I removed the second overload which was not present initially. I didn't think of all the confusion this may generate (and break existing answers). – Walter Jul 06 '17 at 18:22

2 Answers2

7

If you want to deduce the type of parameter, you might use templates to do that:

namespace detail
{
    template<typename>
    struct Helper;

    template<typename R, typename C, typename T>
    struct Helper <R(C::*)(T)>
    {
        using type = T;
    };
}

Then use it like:

detail::Helper<decltype(&MyClass::get_value)>::type value;
// ...
const auto error = my_class.get_value(value);

See related question for more details.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
  • You could automate that into a nice little `template` function that takes a pointer to member of `MyClass` as template parameter, a pointer to `MyClass` as argument, calls said function, checks the error code, throws if no 'success', and returns the value. – Walter Jul 06 '17 at 15:33
  • First, for OP's case, you should apply `std::remove_reference_t` to the type. – Jarod42 Jul 06 '17 at 18:10
  • Second, in OP's case with overload, that won't work. – Jarod42 Jul 06 '17 at 18:10
  • @Jarod42 I agree with `std::remove_reference_t`. As for the second, you might see, that the original answer had no overloads, they appeared after an inaccurate edit when the answer had been already posted. – Edgar Rokjān Jul 06 '17 at 18:14
1

A more compact solution that doesn't require to fully define a new type.

You can use a function declaration (no definition required) and decltype to do that.
It follows a minimal, working example:

#include<type_traits>

template<typename R, typename C, typename T>
constexpr T f(R(C::*)(T));

struct S {
    void f(int) {}
};

int main() {
    static_assert(std::is_same<int, decltype(f(&S::f))>::value, "!");
}

You can also extend it to multiple parameters quite easily by using a tuple:

template<typename R, typename C, typename... T>
constexpr std::tuple<T...> f(R(C::*)(T...));

In C++17 you can also get a more user-friendly type handler using auto template parameter:

template<auto M>
using Type = decltype(f(M));

And use it as:

static_assert(std::is_same_v<int, Type<&S::f>>);
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • @Jarod42 I don't get you. [It works](https://wandbox.org/permlink/3e8NJq3S22IZqqZ9) indeed. What do you mean? I can improve the answer, but first I must get your comment... – skypjack Jul 06 '17 at 20:39
  • `f(int)` vs `f(char)`, but indeed it handles some overloads (except the variadic version). – Jarod42 Jul 06 '17 at 20:46
  • @Jarod42 Well, the example code contains `f()` vs `f(T)`, not `f(T)` vs `f(U)`. The answer is valid for that piece of code, that is a minimal example of the real code as far as I know. I agree that it wouldn't work for what you mentioned anyway. – skypjack Jul 06 '17 at 20:58