提问人:Aditya Garg 提问时间:7/31/2023 最后编辑:JeJoAditya Garg 更新时间:8/1/2023 访问量:99
为什么我需要默认求和函数来获取可变参数模板求和?
Why I need default sum function, for a variadic template sum?
问:
我想计算给定给函数的任意数量的参数的总和。假设给定给函数的整数将满足 。sum
operator+
如果我注释掉函数(没有参数的函数),代码就不会编译。如果我取消注释,代码确实会编译并运行,但永远不会命中函数。sum()
sum()
我似乎不明白为什么我们需要有功能,因为我正在使用条件sum()
sizeof...(Args)
如果有人能帮助我理解这一点,我会不胜感激吗?
/*
int sum()
{
std::cout << "Sum with 0 Args" << std::endl;
return 0;
}
*/
template <typename T, typename...Args>
T sum(T first, Args...args)
{
// std::cout << sizeof...(Args) << std::endl;
if (sizeof...(Args) != 0)
{
return first + sum(args...);
}
else
{
std::cout << "Found 0 args" << std::endl;
return first;
}
}
int main()
{
std::cout << sum(1, 2, 3) << std::endl;
std::cout << sum(1.2, 3.5) << std::endl;
return 0;
}
一旦我取消注释函数sum(),我得到以下输出 -
Found 0 args
6
Found 0 args
4.7
基本上从来没有被叫到这是预期的,但是为什么我们首先需要它呢?sum()
答:
从 C++17 开始,您可以对递归位使用 fold 表达式,并且必须使用 if constexpr 进行编译时 if。
#include <iostream>
template<typename... args_t>
auto sum(args_t&&... args)
{
if constexpr (sizeof...(args_t) == 0)
{
return 0;
}
else
{
return (args + ...);
}
}
int main()
{
std::cout << sum() << "\n";
std::cout << sum(1, 2, 3);
return 0;
}
评论
return (0 + ... + args);
我之前错过了 C++ 11 的要求。下面是一个应该与 C++ 兼容的示例。在这里演示 : https://onlinegdb.com/js_WXEeiC
#include <iostream>
namespace details
{
template<typename arg1_t>
inline constexpr bool same_type()
{
return true;
}
template<typename arg1_t, typename arg2_t, typename... args_t>
inline constexpr bool same_type()
{
return std::is_same<arg1_t, arg2_t>::value && same_type<arg2_t, args_t...>();
}
template<typename arg_t>
arg_t sum(arg_t value)
{
return value;
}
template<typename arg_t, typename... args_t>
arg_t sum(arg_t value, args_t... values)
{
return value + sum(std::forward<args_t>(values)...);
}
}
template<typename arg_t, typename... args_t>
auto sum(arg_t value, args_t... values)
-> typename std::enable_if<details::same_type<arg_t, args_t...>(), arg_t>::type
{
return details::sum(value, values...);
}
int main()
{
static_assert(details::same_type<int>());
static_assert(details::same_type<int, int>());
static_assert(details::same_type<int, int, int>());
static_assert(!details::same_type<int, int, double>());
std::cout << sum(1, 2, 3);
return 0;
}
基本上从来没有被叫过,这是意料之中的,但为什么我们首先需要它呢?
sum()
当您使用普通语句时,就像在代码中一样,这两个分支都会被检查,并且都必须是可编译的。当以递归方式调用 时,最后一个函数调用不带参数。要使这种情况成立,编译器需要一个没有参数的函数。if
sum
sum
另一方面,从 c++17 开始,我们有 if constexpr
,通过它我们可以在编译时只保留真正的分支。这意味着,只需按如下方式更改代码,您就不再需要 with no 参数了。sum()
在这里阅读更多: if constexpr
和 if
之间的区别?
template <typename T, typename...Args>
T sum(T first, Args...args)
{
if constexpr (sizeof...(Args) != 0)
// ^^^^^^^^^^
{
// .... as before
}
else {
// .... as before
}
}
但是,在 c++11 或 c++14 中,您可以通过稍微棘手/笨拙的折叠表达式来实现单个函数†:sum
#include <type_traits> // std::common_type
template <typename...Args>
auto sum(Args...args) -> typename std::common_type<Args...>::type
{
using unused = int[];
typename std::common_type<Args...>::type total{};
return static_cast<void>(unused{ 0, (total += args, 0)...}), total;
}
†引用:
评论
if constexpr
if constexpr