可变模板功能

时间:2015-09-21 19:54:29

标签: c++ templates c++11 variadic-templates

我希望能够将一个可变数量的函数指针传递给模板函数,比如<?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1920 600" enable-background="new 0 0 1920 600" xml:space="preserve"> <g> <polygon fill="none" stroke="#B24539" points="0,297 0,379.3 26.9,346.1 "/> </g> 。下面的例子显示了我到目前为止所做的事情,但是当我实际传递多个模板参数时它没有编译:

foo

我使用gcc5并且编译器吐了:

#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! } ,然后是另一条错误消息:

error: no matching function for call to 'foo(double&)' std::cout << x << '\t' << foo<std::sin, std::asin>(x) << std::endl; ^

有什么想法吗?

1 个答案:

答案 0 :(得分:5)

只需使用扩展器就可以在不使用递归的情况下更简单:

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!