我希望能够将一个可变数量的函数指针传递给模板函数,比如<?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;
^
有什么想法吗?
答案 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!