可变模板功能

Rez*_*aee 3 c++ templates variadic-templates c++11

我希望能够将可变数量的函数指针传递给模板函数,比方说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!
}
Run Code Online (Sandbox Code Playgroud)

我正在使用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; ^

有什么想法吗?

Pio*_*cki 6

你可能意味着这个:

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

DEMO


Bar*_*rry 5

只需使用扩展器就可以在不使用递归的情况下更简单地执行此操作:

using FPtrType = double(*)(double);

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

这通常适用于空参数包,因为没有任何东西被调用,因此隐含身份而无需为其提供自己的功能.否则,这将迭代Func地连续调用每个.

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

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

这将被称为:

foo(x, static_cast<FPtrType>(std::sin), static_cast<FPtrType>(std::asin));
Run Code Online (Sandbox Code Playgroud)

后者的优点是现在你可以传递更复杂的东西.类似于其他类型或任何其他任意可调用的函数:

foo(x, [](double d){return d+1;}); // ok!
Run Code Online (Sandbox Code Playgroud)