16

According to cppreference.com all of the follwing three: argument_type, first_argument_type and second_argument_type are deprecated in C++17 and removed in C++20.

What is the standard library replacement for those member types? I mean I could write my own type traits, but I doubt that something gets removed without having a proper replacement in the standard library.

As an example:

template <typename F> 
void call_with_user_input(F f) {
    typename F::first_argument_type x;  // what to use instead ??
    std::cin >> x;
    f(x);
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • You can create a traits for that. As bonus, your method would work then with lambda too. – Jarod42 Sep 28 '18 at 13:35
  • related/dupe: https://stackoverflow.com/questions/22630832/get-argument-type-of-template-callable-object. – NathanOliver Sep 28 '18 at 13:37
  • @NathanOliver top answer says "[...] you cannot get its argument type" which isnt really a replacement for `argument_type` ;) – 463035818_is_not_an_ai Sep 28 '18 at 13:39
  • @user463035818 Do you want `F` to be any callable type or is it still a `std::function`? I ask because `first_argument_type` only existed for `std::function`. lambda's, functions, and most functors don't have it. And, like the first answer shows, I don't think it is generically possible because the `operator()` can be overloaded. – NathanOliver Sep 28 '18 at 13:43
  • @NathanOliver only `std::function`, sorry if that isnt clear, didnt want to overcomplicate the example – 463035818_is_not_an_ai Sep 28 '18 at 13:44
  • 1
    So `template void call_with_user_input(std::function f)` :-) As bonus can handle more than the only 2 first args. – Jarod42 Sep 28 '18 at 13:45

4 Answers4

3

You can get the type by introducing template parameters

template <typename Ret, typename Arg> 
void call_with_user_input(std::function<Ret(Arg)> f) {
    Arg x;
    std::cin >> x;
    f(x);
}

Gives you the argument type as a template parameter. As a bonus you also get the return type if you need it.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • actually now i wonder why there was a `first_argument` in the first place. Seems like removing it doesnt really have substantial consequences – 463035818_is_not_an_ai Sep 28 '18 at 13:48
  • 2
    @user463035818 It was needed for a lot of old C++03 mechanics that have since been removed. See this for more: https://stackoverflow.com/questions/35907454/why-stdfunctionargument-type-has-been-deprecated – NathanOliver Sep 28 '18 at 13:49
  • "In fact, these typedefs are worse than useless..." thats what finally convinced me. I was misled to believe they are needed for something – 463035818_is_not_an_ai Sep 28 '18 at 13:51
  • @user463035818 I think it would have been useful to have an `arguments_type` type as a tuple of `Arg`... introducing more template parameters can be cumbersome sometimes, and it would make sense since there is already `result_type`. – jdehesa Sep 28 '18 at 13:53
2

From my understanding they are going to be removed and that's it. I found the proposal here.

Related to first_argument_type and second_argument_type:

The adaptable function bindings were a strong candidate for removal in C++17, but were retained only because there was no adequate replacement for users of the unary/binary negators to migrate to. That feature, std::not_fn, was added to C++17 to allow the migration path,

Checking the std::not_fn for c++17 i found that:

Note that the adaptable function protocol no longer functions as well when it was originally designed, due to the addition of new language features and libraries, such as lambda expressions, "diamond" functors, and more. This is not due to a lack of effort, but simply that it is not possible to have a unique set of typedefs for some of these types, such as polymorphic lambda objects. However, we do pay a cost for retaining support elsewhere in the library, due to the awkward conditionally defined member typedefs in several components, such as std::function wrapping a function type with exactly one or two parameters, or similarly for std::reference_wrapper for function references of exactly one or two arguments.

This mean that they are going to just be removed.

One of the problems with first_argument_type and second_argument_type seems to be because of polymorphic lambda objects.

Also as pointed in the comments, anything with multiple operator() that can be passed to std::variant<...>::visit have a problem with first_argument_type

Raxvan
  • 6,257
  • 2
  • 25
  • 46
  • 1
    Anything with multiple `operator()`s, not just polymorphic lambdas. Which is **anything** that you can usefully pass to `std::variant<...>::visit` – Caleth Sep 28 '18 at 14:05
1

One way is to use boost::function_types:

#include <boost/function_types/parameter_types.hpp>
#include <boost/mpl/at.hpp>

template <typename F> 
void call_with_user_input(F f) {
    using FnType = decltype(&F::operator());
    using FirstArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FnType>, 0>::type;
    FirstArgType x;
    std::cin >> x;
    f(x);
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
0

Unfortunately I believe this has to be done with standard SFINAE type_trait implementation techniques. Here is an example replacement for first_argument_type which should be fairly trivial to extend to extracting all template arguments or any specific template argument.

I suspect for most uses of this you would want to decay the template type, however I do not know if the standard implementation decayed it.

#include <functional>
#include <tuple>

template<typename... T>
struct extract_first_arg_type;

template<typename RetType, typename... ValTypes> 
struct extract_first_arg_type<std::function<RetType(ValTypes...)>> {
    using type = std::decay_t<std::tuple_element_t<0, std::tuple<ValTypes...>>>;
};


std::function<void(int, double)> f = [](int k, double d) {};
static_assert(std::is_same_v<extract_first_arg_type<decltype(f)>::type, int>, "");
static_assert(!std::is_same_v<extract_first_arg_type<decltype(f)>::type, double>, "");

(godbolt link)

Chuu
  • 4,301
  • 2
  • 28
  • 54