可变参数函数模板,其参数作为模板非类型传递

时间:2019-03-07 21:45:38

标签: c++ variadic-templates

C ++ 17标准提到了一个独特的可变参数函数模板

  • 不使用常规函数参数,而是
  • 采用非类型模板参数,

就像f<200, 50, 6>() == 256

我认为,这很奇怪,让我看看我是否可以自己编写代码。我的代码很优雅。但是,我的优雅代码无法编译,因此在两个徒劳的小时之后,我编写了以下丑陋的代码:

#include <iostream>

namespace {
    template<int A> constexpr int f() {return A;}
    template<int A, int B, int... C> constexpr int f() {
        if (sizeof...(C)) return A + f<B, C...>();
        else return A + B;
    }
}

int main() {
    int n = f<200, 50, 6>();
    std::cout << n << "\n";
    return 0;
}

这个丑陋的代码有效,而且很有趣,因为它偶然地教了我sizeof...()。但是,这不对吗?

每次我尝试更简单的操作时,编译器都会大惊小怪,抱怨名称查找冲突或模板重新定义或其他类似的事情。

我的想法感觉不对。我怀疑我错过了重点。请问我错过了哪一点?

参考

有关信息,在标准(草稿here)中,引起我问题的部分是宗派。 5.13.8(第3和第4段)。但是据我所知,这种挑衅是偶然的。我的问题不是关于这样的标准。我的问题是关于适当而优雅地使用变异函数。

非编译示例

如果您想要我更优雅,更未经编译的代码示例,请参考以下示例:

namespace {
    template<> constexpr int f() {return 0;}
    template<int A, int... C> constexpr int f() {
        return A + f<C...>();
    }
}

阅读了编译器的错误消息后,我理解了为什么此特定代码失败,所以这不是我的问题。我的问题是,

  • f<200, 50, 6>()这样的可变参数调用应如何正确实施,并且
  • 因此,我对于C ++变量缺少什么概念。

1 个答案:

答案 0 :(得分:5)

编写函数的C ++ 17方法是

template<auto... Vals>
constexpr auto sum() noexcept(noexcept((Vals + ...)))
{
    return (Vals + ...);
}

其中template<auto... Vals>表示我们有一个可变的值模板,而(Vals + ...)是一个fold expression,它将所有值相加(外部()要求有效的折叠表达式)。

我使用了auto...,因此它不仅限于特定类型。如果需要,可以添加SFINAE来将模板限制为仅支持加法的类型,否则,如果不能将参数包中的所有类型都不能加在一起,则会出现编译器错误。