我正在尝试在C ++中实现划分的差异公式,因为它显示为here。
到目前为止,我已经来了这个
template<typename F, typename T>
T divdiff(F f, T t1, T t2) {
return (f(t1) - f(t2)) / (t1 - t2);
};
template<typename F, typename T, typename... Args>
T divdiff(F f, T tstart, Args... t, T tend) {
return (divdiff(f, tstart, t...) - divdiff(f, t..., tend))/ (tstart - tend);
};
它编译得很好但是当它尝试使用它时,例如像这样
double r = divdiff([](double x) { return 2 * x; }, 1.0, 2.0, 3.0);
我收到以下错误
note: candidate function not viable: requires 3 arguments, but 4 were provided
T divdiff(F f, T tstart, Args... t, T tend) {``
我的编译器是gcc
配置: - prefix = / Library / Developer / CommandLineTools / usr --with-gxx-include-dir = / usr / include / c ++ / 4.2.1 Apple LLVM 8.0.0版(clang-800.0.42.1)目标:x86_64-apple-darwin15.4.0线程模型: posix InstalledDir:/ Library / Developer / CommandLineTools / usr / bin
有谁知道它为什么不起作用以及如何解决它
答案 0 :(得分:2)
template<typename F, typename T, typename... Args> T divdiff(F f, T tstart, Args... t, T tend)
由于Args... t
不在参数列表的末尾,因此不会推导出它。这种推论不允许部分简化语言规则,部分是为了帮助保持程序简单(并防止自己在脚下射击。)你可以明确指定Args ...
像divdiff<F, double, double>
,但随后为递归要求删除最后一个double
。
在任何情况下,可变参数模板方法都会遭受模板膨胀,并且效率低下,因为参数列表可能会被每个函数调用复制。由于序列的元素应该都是相同的类型,因此请考虑使用迭代器。然后,您可以使用std::initializer_list
为基于数组的可迭代序列添加方便重载。
template< typename F, typename bidirectional_iterator >
typename std::iterator_traits< bidirectional_iterator >::value_type
divdiff( F f, bidirectional_iterator first, bidirectional_iterator last ) {
bidirectional_iterator next = std::next( first );
bidirectional_iterator prev = std::prev( last );
auto diff = next == prev?
f( * first ) - f( * prev )
: divdiff( f, first, prev ) - divdiff( f, next, last );
return diff / ( * first - * prev );
}
template< typename F, typename T >
T divdiff( F f, std::initializer_list< T > il )
{ return divdiff( f, il.begin(), il.end() ); }
答案 1 :(得分:0)
这是标准的,元组解包的递归解决方案。 我改变了你的lambda,因为线性函数在这里有点无聊。
#include <iostream>
#include <utility>
#include <tuple>
// The base version of divdiff, ends recursion
template<typename F, typename T>
T divdiff(F f, T t0, T t1) {
return (f(t0) - f(t1)) / (t0 - t1);
}
// This divdiff overload takes a tuple and an index sequence
// The index sequence specifies which elements from the tuple will
// be unpacked as arguments for a divdiff call
template <typename F, typename T, std::size_t... Is>
auto divdiff(F f, T arg_tuple, std::index_sequence<Is...>) {
return divdiff(f, std::get<Is>(arg_tuple)...);
}
template<typename F, typename T, typename ...Ts>
T divdiff(F f, T t0, Ts ...right_args) {
// pack all arguments into a tuple
auto arg_tuple = std::make_tuple(t0, right_args...);
// make an index sequence whose size is one less than the
// current recursion's argument count
using next_index_sequence = std::make_index_sequence<sizeof...(Ts)>;
// get the value of the final argument in tn
auto tn = std::get<sizeof...(Ts)>(arg_tuple);
// Call divdiff, first using the tuple/sequence overload for the left
// side arguments.
// Then call it with the easily-obtained right side arguments.
return (divdiff(f, arg_tuple, next_index_sequence{})
- divdiff(f, right_args...)) / (t0 - tn);
}
int main() {
double r = divdiff([](double x) { return x * x * x; }, 1.0, 2.0, 3.0);
std::cout << r << '\n';
}