Search code examples
c++variadic-functions

get the first with specific type in a variadic function


this is my 2nd post and i tried to find as much information before posting here as i could (including the new possibility with chatgpt) to understand some more the work of variadic function. The first try runs well where i checked if the given argument list includes a sepcific typ of argument.

template<typename T, typename Arg>
auto hasType(Arg arg) -> bool {
  return std::is_same<T, decltype(arg)>::value;
}

template <typename T, typename... Args>
auto hasType(Args... args) {
  return (hasType<T>(args) || ...);
}

// call like
std::string thisIsATest = "this is a test";
hasType<float>(thisIsATest, "Hello, world!", 5.67, 452);

Now the next step was getting the value of the first specific argument. I created 2 new variadic methods:

// The fall back if there is none of the specific type i search
template<typename T>
auto getFirst() -> T {
  throw someCustomException("Argument list not including the specific type.");
}

template<typename T, typename Arg, typename... Args>
auto getFirst(Arg arg, Args... args) -> T {
  // test if arg is not the same type and call recursive the function with
  // next argument
  if (!(std::is_same<T, decltype(arg)>::value)) {
    return getFirst<T>(args...);
  }
  // the arg should now match the condition to match type with T
  return arg;
  //-----^--- Multiple Errors like : could not convert ‘arg’ from ‘int’ to ‘std::__cxx11::basic_string<char>’ Or error: could not convert ‘arg’ from ‘double’ to ‘std::__cxx11::basic_string<char>’ 
}

The idea is to call getFirst like that:

std::string thisIsATest = "This is a test";
std::string thisIsAnOtherString = "This is an other string";
int intValue = 5;
double doubleValue = 28.563;
auto result = getFirst<std::string>(5, 1.2567, intValue, true, thisIsATest, doubleValue, false, 945.621, thisIsAnOtherString);
// result = thisIsATest

There are some changes i tried, like:

  • changing the return type of getFirst from T to Arg (other errors when calling "return getFirst(args...);")
  • changing first argument from value to reference => same errors provided in example
  • trying to cast arg to type T but didn't found a working posibility

In the moment i'm a litle bit stucked in the hole variadic topic, where to make the necessary changes to reach the functionality or if this is reachable at all. Maybe someone can help me here.

Thanks.

Edit: There was just a little change in my local code which holds the solution from working correctly.


Solution

  • auto return type deduction requires the type deduced from different return statements to match. Yours don't. You use if constexpr to have the false branch discarded, then there is no issue with deducing the return type:

    template<typename T, typename Arg, typename... Args>
    auto getFirst(Arg arg, Args... args) -> T {
      if constexpr  (!(std::is_same<T, decltype(arg)>::value)) {
        return getFirst<T>(args...);
      } else {
        return arg;
      }
    }
    

    Complete Example