1

Below code extracts n-th argument of function formatted as string. How can I implement it without providing the second function? Is it possible at all?

template <typename Type, typename ...Args>
static std::string getArgument(unsigned argumentIndex, Type value, Args... args)
{
    if (argumentIndex != 0)
        return getArgument(argumentIndex - 1, args...);
    else
        return std::to_string(value);
}

static std::string getArgument(unsigned argumentIndex)
{
    return std::string();
}
no one special
  • 1,608
  • 13
  • 32
  • I don't think you can. You could if `argumentIndex` were a template argument. – tkausl Apr 14 '23 at 17:27
  • 2
    @RemyLebeau Only if all `Args` are of the same type unfortunately. I thought of using a tuple, but indexing it won't work with a non-constant-expression. Edit: Well, you could just stringify __all__ args and create an array of `std::string`s but that might be a lot of wasted cycles depending on the types. – tkausl Apr 14 '23 at 17:32
  • @Drew Your `if constexpr` approach was correct, just needed a little rearranging to handle the erroneous indexes. – Ben Voigt Apr 14 '23 at 17:48

1 Answers1

1

Thanks @DrewDormann for getting the solution started. Here it is, rearranged to have the behavior of the original code for index-out-of-range:

template <typename Type, typename ...Args>
static std::string getArgument(unsigned argumentIndex, Type value, Args... args)
{
    if (argumentIndex == 0)
        return std::to_string(value);
    if constexpr ( sizeof...(Args) > 0 ) {
        return getArgument(argumentIndex - 1, args...);
    }
    return std::string();
}

The one-argument overload of the function is eliminated; a consequence is that the user can't call the function with only the argumentIndex. My understanding of the question is that OP wanted this change.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • What about the case where there is no `value` to pass in? Without converting `args` to a local array, the only way I know to skip the front value of `args` is with a recursive call to an explicit parameter outside of the pack (as this code shows), but you would still need an overload where such a parameter is not available (as the OP's code shows) otherwise calling `getArgument(index)` is not valid. – Remy Lebeau Apr 14 '23 at 18:00
  • @RemyLebeau: The `if constexpr` condition prevents reaching that condition during recursion, and OP seems to want to prevent the user from failing to initially provide any values. – Ben Voigt Apr 14 '23 at 18:03
  • "*OP seems to want to prevent the user from failing to initially provide any values*" - I don't see anything in the OP's question to suggest that. Whether or not letting users call `getArgument(index)` without values *makes sense* is a different matter. But the OP's code did allow that, whereas this solution does not. – Remy Lebeau Apr 14 '23 at 18:04
  • @RemyLebeau: He wanted to eliminate the second overload. Since that's the thing that permits calling with no values, I surmise that prohibiting a call without values is either the whole reason to want to eliminate the second overload, or at least acceptable to OP. – Ben Voigt Apr 14 '23 at 18:05
  • Thank you for the code. It is something that i was looking for. Reading your comments - is it also possible to support the case when there are no arguments specified? – no one special Apr 14 '23 at 18:20
  • 1
    @noonespecial: Your original code already does. Behavior of a call with no values (enter out-of-range case vs compile error) is the reason you would choose one or the other implementation. – Ben Voigt Apr 14 '23 at 18:23
  • fair enough. Thank you then! – no one special Apr 14 '23 at 18:24