获取可变参数函数中特定类型的第一个。

huangapple go评论62阅读模式
英文:

get the first with specific type in a variadic function

问题

这是我的第二篇帖子,我在发布之前尽力寻找了尽可能多的信息(包括使用ChatGPT的新可能性),以更好地理解可变参数函数的工作方式。第一次尝试成功,我检查了给定的参数列表是否包含特定类型的参数。

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) || ...);
}

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

现在下一步是获取第一个特定参数的值。我创建了两个新的可变参数方法:

// 如果没有找到特定类型,使用此回退方法
template<typename T>
auto getFirst() -> T {
  throw someCustomException("参数列表不包含特定类型。");
}

template<typename T, typename Arg, typename... Args>
auto getFirst(Arg arg, Args... args) -> T {
  // 测试如果arg的类型与T不同,就递归调用带有下一个参数的函数
  if (!(std::is_same<T, decltype(arg)>::value)) {
    return getFirst<T>(args...);
  }
  // arg现在应该满足与T匹配的条件
  return arg;
}

调用getFirst的方式如下:

std::string thisIsATest = "This is a test";
std::string thisIsAnOtherString = "This is another 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

我尝试了一些更改,比如:

  • 将getFirst的返回类型从T更改为Arg(调用"return getFirst(args...);"时会出现其他错误)
  • 将第一个参数从值更改为引用 => 与示例中提供的相同错误
  • 尝试将arg转换为类型T,但没有找到有效的方法

目前,我在可变参数主题中有些困惑,不确定要进行哪些必要更改以实现所需的功能,或者是否可以达到这个目标。也许有人可以在这里帮助我。

谢谢。

编辑:在我本地的代码中只有一个小变化,这个变化导致了无法正常工作的解决方案。

英文:

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&lt;typename T, typename Arg&gt;
auto hasType(Arg arg) -&gt; bool {
  return std::is_same&lt;T, decltype(arg)&gt;::value;
}

template &lt;typename T, typename... Args&gt;
auto hasType(Args... args) {
  return (hasType&lt;T&gt;(args) || ...);
}

// call like
std::string thisIsATest = &quot;this is a test&quot;;
hasType&lt;float&gt;(thisIsATest, &quot;Hello, world!&quot;, 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&lt;typename T&gt;
auto getFirst() -&gt; T {
  throw someCustomException(&quot;Argument list not including the specific type.&quot;);
}

template&lt;typename T, typename Arg, typename... Args&gt;
auto getFirst(Arg arg, Args... args) -&gt; T {
  // test if arg is not the same type and call recursive the function with
  // next argument
  if (!(std::is_same&lt;T, decltype(arg)&gt;::value)) {
    return getFirst&lt;T&gt;(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&lt;char&gt;’ Or error: could not convert ‘arg’ from ‘double’ to ‘std::__cxx11::basic_string&lt;char&gt;’ 
}

The idea is to call getFirst like that:

std::string thisIsATest = &quot;This is a test&quot;;
std::string thisIsAnOtherString = &quot;This is an other string&quot;;
int intValue = 5;
double doubleValue = 28.563;
auto result = getFirst&lt;std::string&gt;(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<T>(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.

答案1

得分: 3

不要使用std::is_same,使用另一个重载。

template<typename T>
T getFirst() // 递归基本情况
{
    throw whatever();
}

template<typename T, typename... Args>
T getFirst(T& arg, Args... args) // 匹配情况
{
    return arg;
}

template<typename T, typename Arg, typename... Args>
T getFirst(Arg arg, Args... args) // 继续搜索情况
{
    return getFirst(args);
}
英文:

Instead of using std::is_same, use another overload.

template&lt;typename T&gt;
T getFirst() // recursion base case
{
    throw whatever();
}

template&lt;typename T, typename... Args&gt;
T getFirst(T&amp; arg, Args... args) // matching case
{
    return arg;
}

template&lt;typename T, typename Arg, typename... Args&gt;
T getFirst(Arg arg, Args... args) // continuing the search case
{
    return getFirst(args);
}

答案2

得分: 3

auto 返回类型推断要求从不同的 return 语句中推断出的类型匹配。你的代码没有匹配。你可以使用 if constexpr 来丢弃 false 分支,然后就没有关于返回类型的问题:

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;
  }
}

完整示例

英文:

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&lt;typename T, typename Arg, typename... Args&gt;
auto getFirst(Arg arg, Args... args) -&gt; T {
  if constexpr  (!(std::is_same&lt;T, decltype(arg)&gt;::value)) {
    return getFirst&lt;T&gt;(args...);
  } else {
    return arg;
  }
}

Complete Example


huangapple
  • 本文由 发表于 2023年2月18日 02:40:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75488156.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定