计算通过模板传递的所有参数(非类型参数)的总和
Calculate the sum of all arguments(non-type parameters) passed through a template
我想计算通过模板传递的所有参数(非类型参数)的总和。我编译了以下程序:g++ -std=c++17 -g -Wall -o main main.cpp。似乎我错过了什么,因为我在编译时遇到了这个错误:
error: call of overloaded ‘func<N_0>()’ is ambiguous
std::cout << func<N_0>() << std::endl;
error: call of overloaded ‘func<22>()’ is ambiguous
return N + func<Next... >();
#include <iostream>
using namespace std;
template <std::size_t T>
std::size_t sum()
{
return T;
}
template <std::size_t N, std::size_t ...Next>
std::size_t sum()
{
return N + sum<Next... >();
}
int main()
{
const size_t N_0 = 4;
const size_t N_1 = 11;
const size_t N_2 = 22;
std::cout << sum<N_0>() << std::endl;
std::cout << sum<N_0, N_1, N_2>() << std::endl;
return 0;
}
我发现了很多这样的例子:
#include <iostream>
template<typename T>
T adder(T first) {
return first;
}
template<typename T, typename... Args>
T adder(T first, Args... args) {
return first + adder(args...);
}
int main() {
const int c = adder(1, 8, 4);
std::cout << c << '\n';
return 0;
}
我很好奇为什么我的代码不起作用。
在第一个和第二个代码示例中,仅使用一个(模板)参数调用函数会导致两个函数模板都可行。这些包将是空的。
但是,在第二个示例的重载决策中,可变参数模板被认为不如非可变参数模板专业化,主要是因为调用它的可能参数集是非可变参数模板的超集可以调用。这只是因为函数参数中的参数包。因此,重载解析将更喜欢非可变模板作为决胜局。
此顺序不适用于您的第一个代码示例,其中两个模板的函数参数相同。
因此,使用单个(模板)参数的重载解析在您的第一个代码示例中不明确,但在第二个代码示例中不明确。
您可以指定可变参数模板至少需要两个参数来解决歧义:
template <std::size_t N, std::size_t M, std::size_t ...Next>
std::size_t sum()
{
// May wrap-around to zero
return N + sum<M, Next... >();
}
然而,在 C++17 及更高版本中,整个 sum
构造可以通过使用 折叠表达式 简化为:
template <std::size_t ...Ns>
std::size_t sum()
{
// May wrap-around to zero
return (Ns + ...);
}
(此函数可能在 C++17 中标记为 noexcept
和 constexpr
,或者在 C++20 中标记为 consteval
,并且应注意 many/large参数,因为如果总和变得太大以至于 std::size_t
无法容纳,加法将默默地回绕。)
我想计算通过模板传递的所有参数(非类型参数)的总和。我编译了以下程序:g++ -std=c++17 -g -Wall -o main main.cpp。似乎我错过了什么,因为我在编译时遇到了这个错误:
error: call of overloaded ‘func<N_0>()’ is ambiguous
std::cout << func<N_0>() << std::endl;
error: call of overloaded ‘func<22>()’ is ambiguous
return N + func<Next... >();
#include <iostream>
using namespace std;
template <std::size_t T>
std::size_t sum()
{
return T;
}
template <std::size_t N, std::size_t ...Next>
std::size_t sum()
{
return N + sum<Next... >();
}
int main()
{
const size_t N_0 = 4;
const size_t N_1 = 11;
const size_t N_2 = 22;
std::cout << sum<N_0>() << std::endl;
std::cout << sum<N_0, N_1, N_2>() << std::endl;
return 0;
}
我发现了很多这样的例子:
#include <iostream>
template<typename T>
T adder(T first) {
return first;
}
template<typename T, typename... Args>
T adder(T first, Args... args) {
return first + adder(args...);
}
int main() {
const int c = adder(1, 8, 4);
std::cout << c << '\n';
return 0;
}
我很好奇为什么我的代码不起作用。
在第一个和第二个代码示例中,仅使用一个(模板)参数调用函数会导致两个函数模板都可行。这些包将是空的。
但是,在第二个示例的重载决策中,可变参数模板被认为不如非可变参数模板专业化,主要是因为调用它的可能参数集是非可变参数模板的超集可以调用。这只是因为函数参数中的参数包。因此,重载解析将更喜欢非可变模板作为决胜局。
此顺序不适用于您的第一个代码示例,其中两个模板的函数参数相同。
因此,使用单个(模板)参数的重载解析在您的第一个代码示例中不明确,但在第二个代码示例中不明确。
您可以指定可变参数模板至少需要两个参数来解决歧义:
template <std::size_t N, std::size_t M, std::size_t ...Next>
std::size_t sum()
{
// May wrap-around to zero
return N + sum<M, Next... >();
}
然而,在 C++17 及更高版本中,整个 sum
构造可以通过使用 折叠表达式 简化为:
template <std::size_t ...Ns>
std::size_t sum()
{
// May wrap-around to zero
return (Ns + ...);
}
(此函数可能在 C++17 中标记为 noexcept
和 constexpr
,或者在 C++20 中标记为 consteval
,并且应注意 many/large参数,因为如果总和变得太大以至于 std::size_t
无法容纳,加法将默默地回绕。)