C++ 如何编写可变模板递归函数?

C++ 如何编写可变模板递归函数?,c++,c++11,recursion,variadic-templates,variadic-functions,C++,C++11,Recursion,Variadic Templates,Variadic Functions,我试图编写一个可变模板constepr函数,它计算给定模板参数的总和。这是我的密码: template<int First, int... Rest> constexpr int f() { return First + f<Rest...>(); } template<int First> constexpr int f() { return First; } int main() { f<1, 2, 3>();

我试图编写一个可变模板
constepr
函数,它计算给定模板参数的总和。这是我的密码:

template<int First, int... Rest>
constexpr int f()
{
    return First + f<Rest...>();
}

template<int First>
constexpr int f()
{
    return First;
}

int main()
{
    f<1, 2, 3>();
    return 0;
}
但此代码也不会编译(消息
错误C2912:显式专门化“int f(void)”不是函数模板的专门化

我可以提取第一个和第二个模板参数来编译和工作,如下所示:

template<int First, int Second, int... Rest>
constexpr int f()
{
    return First + f<Second, Rest...>();
}
模板
constexpr int f()
{
先返回+f();
}
但这似乎不是最好的选择。因此,问题是:如何以优雅的方式编写此计算

UP:我还尝试将其作为单个函数编写:

template<int First, int... Rest>
constexpr int f()
{
    return sizeof...(Rest) == 0 ? First : (First + f<Rest...>());
}
模板
constexpr int f()
{
返回sizeof…(Rest)==0?First:(First+f());
}

这也不起作用:
错误C2672:“f”:没有找到匹配的重载函数

template<int... Args>
constexpr int f() {
   int sum = 0;
   for(int i : { Args... }) sum += i;
   return sum;
}
模板
constexpr int f(){
整数和=0;
对于(inti:{Args…})sum+=i;
回报金额;
}

我发现将代码从模板参数移动到函数参数通常更容易:

constexpr int sum() { return 0; }

template <class T, class... Ts>
constexpr int sum(T value, Ts... rest) {
    return value + sum(rest...);
}

它是
constexpr
,所以只需使用
int
s就可以了

你的基本情况是错误的。您需要空列表的案例,但正如编译器所建议的,您的第二次尝试不是有效的模板专门化。为零参数定义有效实例化的一种方法是创建一个接受空列表的重载

template<class none = void>
constexpr int f()
{
    return 0;
}
template<int First, int... Rest>
constexpr int f()
{
    return First + f<Rest...>();
}
int main()
{
    f<1, 2, 3>();
    return 0;
}
模板
constexpr int f()
{
返回0;
}
模板
constexpr int f()
{
先返回+f();
}
int main()
{
f();
返回0;
}

编辑:为了完整性,也是我的第一个答案,@alexeykuzmin0通过添加条件来修复:

template<int First=0, int... Rest>
constexpr int f()
{
    return sizeof...(Rest)==0 ? First : First + f<Rest...>();
}
模板
constexpr int f()
{
返回sizeof…(Rest)==0?First:First+f();
}

解决方案2:使用
constexpr
函数
constexpr int sum(){
返回0;
}
模板
constexpr int sum(第一个是…rest){
返回第一个+和(剩余…);
}

解决方案#3:使用模板元编程
模板
结构和;
模板
结构和
:std::积分常数
{};
模板
结构和
:std::积分常数
{};

使用
std::initializer\u list
的更通用的解决方案是:

template <typename... V>                                                                                                                                                                                         
auto sum_all(V... v)
{
  using rettype = typename std::common_type_t<V...>;
  rettype result{};
  (void)std::initializer_list<int>{(result += v, 0)...};
  return result;
}
模板
自动求和(V…V)
{
使用rettype=typename std::common\u type\t;
rettype结果{};
(void)std::initializer_list{(result+=v,0)…};
返回结果;
}

这与@T.C上面建议的非常相似:

#include<iostream>
#include<numeric>

template<int First, int... Rest>
constexpr int f()
{
    auto types = {Rest...};
    return std::accumulate(std::begin(types), std::end(types),0);   
}

int main()
{
    std::cout <<f<1, 2, 3>();
    return 0;
}
#包括
#包括
模板
constexpr int f()
{
自动类型={Rest…};
返回std::累计(std::开始(类型),std::结束(类型),0);
}
int main()
{

这是我第一次尝试。不幸的是,我的编译器(MSVC++2015)不理解变量在<代码> CONTXPRP</代码>函数中的声明。@ AlxyKuZMIN 0我看到你改变了C++ 14标签。好的,我意识到这个特性的不足意味着我的编译器没有完全支持C++。14@alexeykuzmin0改变问题要求,使发布的答案无效,这通常是不正确的被认为是有礼貌的,因为这让人觉得发布答案的人做得不正确。@jaggedSpire我理解这一点,非常抱歉。但让问题表述错误无助于获得正确的答案。这有点多余,不是吗?如果是constexpr,编译器可以计算express不管怎样,为什么不定义
constexpr int f(int a,…)
?@示例是的,对于这种方法的总和,但在我的实际情况下,函数要复杂一些,需要知道
Rest的长度…
(类似于转换到另一个基)这不能作为一个
constexpr
来评估,因为这样的方法总的来说是有效的,但我的生活有点复杂。问题的表述不正确,所以结束。谢谢你的详细解释。我一直在尝试用字符串来做这件事,似乎不能成功地使用std::stringview来constexpr,而且metap也失败了编程位,我是一个虚拟的还是不可能这样?这需要c++14,而不是11您不能在常量表达式中使用它。尝试使用
constexpr int v=f();
,它不会编译。
template<int First, int... Rest>
constexpr int f()
{
    return First + f<Rest...>();
}

template<int First>
constexpr int f()
{
    return First;
}

int main()
{
    f<1, 2, 3>();
    return 0;
}
error C2668: 'f': ambiguous call to overloaded function while trying to resolve f<3,>() call.
template <>
constexpr int f()
{
    return 0;
}
template <typename... Is>
constexpr int sum(Is... values) {
    return (0 + ... + values);
}
constexpr int sum() {
    return 0;
}

template <typename I, typename... Is>
constexpr int sum(I first, Is... rest) {
    return first + sum(rest...);
}
template <int... Is>
struct sum;

template <>
struct sum<>
    : std::integral_constant<int, 0>
{};

template <int First, int... Rest>
struct sum<First, Rest...>
    : std::integral_constant<int,
        First + sum_impl<Rest...>::value>
{};
template <typename... V>                                                                                                                                                                                         
auto sum_all(V... v)
{
  using rettype = typename std::common_type_t<V...>;
  rettype result{};
  (void)std::initializer_list<int>{(result += v, 0)...};
  return result;
}
#include<iostream>
#include<numeric>

template<int First, int... Rest>
constexpr int f()
{
    auto types = {Rest...};
    return std::accumulate(std::begin(types), std::end(types),0);   
}

int main()
{
    std::cout <<f<1, 2, 3>();
    return 0;
}