【问题标题】:Template parameter denoting "something callable with particular signature"模板参数表示“具有特定签名的可调用对象”
【发布时间】:2018-05-02 00:32:15
【问题描述】:

我希望能够编写这样的代码:

SplineFunction<Polynomial<3>> cubicSplineFunction;
// ... here be some additional code to populate the above object ...

auto dydx = cubicSplineFunction.transform<Polynomial<2>>(const Polynomial<3>& cubicSpline){
    return cubicSpline.derivative();
};

auto dsdx = cubicSplineFunction.transform<T/*?*/>([](const Polynomial<3>& cubicSpline){
    Polynomial<2> dy = cubicSpline.derivative();
    Polynomial<4> dsSquared = dy*dy + 1*1;
    return [dsSquared](double x){ // Fixed in response to comment: capture by value
        return std::sqrt(dsSquared);
    };
});

dydx(1.0); // efficient evaluation of cubicSplineFunction's derivative
dsdx(2.0); // efficient evaluation of cubicSplineFunction's arc rate

所以我实现了下面的类。但是我应该用什么类型代替上面的 T(第 8 行)来表示“可以通过签名 double(double) 调用的东西”?

template<typename S>
struct SplineFunction {

    std::vector<S> splines;

    auto operator()(double t) const {
        int i = static_cast<int>(t);
        return splines[i](t - i);
    }

    template<typename R, typename F>
    SplineFunction <R> transform(F f) const {
        SplineFunction <R> tfs;
        for (const auto& s : splines) {
            tfs.splines.push_back(f(s));
        }
        return tfs;
    }

    // ... MORE CODE ...
}

template<int N>
struct Polynomial {
    std::array<double, N+1> coeffs;
    double operator()(double x) const;
    Polynomial<N - 1> derivative() const;

    // ... MORE CODE ...
}

template<int L, int M>
Polynomial<L+M> operator*(const Polynomial<L>& lhs, const Polynomial<M>& rhs);

template<int L>
Polynomial<L> operator+(Polynomial<L> lhs, double rhs);

// ... MORE CODE ...

【问题讨论】:

  • 危险,威尔罗宾逊!第二个transform 调用创建一个通过引用捕获局部变量的lambda,然后将该lambda 返回给调用者。调用者得到的是一个持有悬空引用的 lambda。
  • "something callable with signature double(double)"可以拼写为std::function&lt;double(double)&gt;
  • 另一种可能性是完全删除R 参数并推断返回类型:template&lt;typename F&gt; auto transform(F f) const -&gt; SplineFunction&lt;decltype(f(std::declval&lt;S&gt;()))&gt; { ... }
  • @IgorTandetnik 您可以使用std::function 拼写它,但只能使用开销(在性能和大小方面)。在这种情况下可能无关紧要,但值得指出。

标签: c++ c++11 templates lambda


【解决方案1】:
template<class F, class R=std::result_of_t<F&(S const&)>>
SplineFunction<R> transform(F f) const

不要显式传递类型;让他们推断出来。

typename std::result_of&lt;F&amp;(S const&amp;)&gt;::type

衰减 R 类型(如 std 衰减)也可能很聪明,因为 SplineFunction 存储其模板参数,而衰减使类型更适合存储。

【讨论】:

  • 在 C++17 中,std::result_of 已被弃用。
  • @daniel 是的;但原因是它很难使用;我正确地使用了它。 C++2a/b 版本是机械改造。
  • 我并不是说你确实用错了;我提倡一般不要使用已弃用的功能(这会使升级变得更加困难),尤其是反对这样做而不注意它已被弃用。虽然在这种情况下,我认为 result_ofinvoke_result 都是错误的工作工具,如果我在一台真正的计算机上,我会将 Igor Tandetnik’s return type deduction suggestion 扩展为完整的答案。
猜你喜欢
  • 2018-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-09
  • 1970-01-01
  • 2014-10-05
相关资源
最近更新 更多