可变模板函数
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);
}
你可以通过扩展器在不使用递归的情况下更简单地做到这一点:
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!
我希望能够将可变数量的 函数指针 传递给模板函数,比如 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);
}
你可以通过扩展器在不使用递归的情况下更简单地做到这一点:
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!