可变模板函数

Variadic Template Functions

我希望能够将可变数量的 函数指针 传递给模板函数,比如 foo。下面的示例显示了我到目前为止所拥有的内容,但是当我实际传递多个模板参数时它无法编译:

#include <iostream>
#include <cmath>

using FPtrType = double(*)(double);
constexpr double Identity( double x ) noexcept { return x; }

template <FPtrType Func=Identity>
constexpr double foo( double x ) noexcept( noexcept( Func(x) ) )
{
    return Func(x);
}
template <FPtrType Func, typename... Funcs>
constexpr double foo( double x, Funcs... funcs )
{
    x = Func(x);
    return foo<Funcs...>(x, funcs...);
}

int main()
{
    double x{ 0.5 };
    std::cout << x << '\t' << foo(x) << std::endl;  // OK
    std::cout << x << '\t' << foo<std::sin>(x) << std::endl;  // OK
    std::cout << x << '\t' << foo<std::asin>(x) << std::endl;  // OK
    std::cout << x << '\t' << foo<std::sin, std::asin>(x) << std::endl; // Error!
}

我正在使用 gcc5,编译器喷出:

error: no matching function for call to 'foo(double&)' std::cout << x << '\t' << foo<std::sin, std::asin>(x) << std::endl; ^ ,后跟另一个错误信息:

error: wrong number of template arguments (2, should be at least 0) std::cout << x << '\t' << foo<std::sin, std::asin>(x) << std::endl; ^

有什么想法吗?

你可能是这个意思:

template <FPtrType Func, FPtrType Func2, FPtrType... Funcs>
constexpr double foo( double x )
{
    x = Func(x);
    return foo<Func2, Funcs...>(x);
}

DEMO

你可以通过扩展器在不使用递归的情况下更简单地做到这一点:

using FPtrType = double(*)(double);

template <FPtrType... Funcs>
constexpr double foo( double x )
{
    using expander = int[];
    expander{0,
        (x = Funcs(x), 0)...
    };
    return x;
}

这对于空参数包非常有效,因为从未调用过任何东西,因此无需为它提供您自己的函数就隐含了身份。否则,这将迭代地连续调用每个 Func

您还可以使用相同的方法将它们作为参数而不是模板非类型参数:

template <typename... Fs>
constexpr double foo(double x, Fs... Funcs)
{
    using expander = int[];
    expander{0,
        (x = Funcs(x), 0)...
    };
    return x;
}

这样称呼:

foo(x, static_cast<FPtrType>(std::sin), static_cast<FPtrType>(std::asin));

后者的优点是现在你可以传入更复杂的东西。像采用其他类型或任何其他任意可调用函数的函数:

foo(x, [](double d){return d+1;}); // ok!