【问题标题】:Generically taking linear combinations of indexibles/callables一般采用可索引/可调用的线性组合
【发布时间】:2020-06-08 13:16:38
【问题描述】:

我正在尝试全局缩放并将可调用/可索引对象(抽象数学意义上的向量)相加。

也就是说,我正在尝试对定义 operator[]operator() 的对象进行线性组合。

例如,我希望能够做到这一点:

LinearCombination<std::function<double(double, double)>> A([](double x, double y){
    return 1+x+std::pow(x,2)+std::sin(y);
});
LinearCombination<std::function<double(double, double)>> B([](double x, double y){
    return 1-x+std::cos(y);
});
A*= 2.5;
A += B;
std::cout << A(1.0,2.0) << std::endl;

我的尝试

// ZERO ///////////////////////////////////////////////////////////////////////////////////////////

namespace hidden {

    // tag dispatching: from https://stackoverflow.com/a/60248176/827280

    template<int r>
    struct rank : rank<r - 1> {};

    template<>
    struct rank<0> {};

    template<typename T>
    auto zero(rank<2>) -> decltype(static_cast<T>(0)) {
        return static_cast<T>(0);
    }

    template<typename T>
    auto zero(rank<1>) -> decltype(T::zero()) {
        return T::zero();
    }

    template<typename T>
    auto zero(rank<0>)->std::enable_if_t<
        std::is_assignable<std::function<double(double,double)>, T>::value
        , std::function<double(double,double)>> {
        return []() {
            return 0.0;
        };
    }
}

template<typename T>
auto zero() { return hidden::zero<T>(hidden::rank<10>{}); }

// LINEAR COMBINATION ///////////////////////////////////////////////////////////////////////////////////////////

template<typename V, typename C = double>
struct LinearCombination {
    struct Term {
        C coeff;
        V vector;

        // if V(x...) is defined
        template<typename ...X>
        auto operator()(X&&... x) const -> std::remove_reference_t<decltype(std::declval<V>()(std::forward<X>(x)...))> {
            return vector(std::forward<X>(x)...) * coeff;
        }

        // if V[i] is defined
        template<typename I>
        auto operator[](I i) const -> std::remove_reference_t<decltype(std::declval<V>()[i])> {
            return vector[i] * coeff;
        }

    };
    std::vector<Term> terms;

    LinearCombination() {} // zero

    /*implicit*/ LinearCombination(V&& v) {
        terms.push_back({ static_cast<C>(1), std::move(v) });
    }

    /*implicit*/ LinearCombination(Term&& term) {
        terms.push_back(std::move(term));
    }

    LinearCombination<V, C>& operator+=(LinearCombination<V, C>&& other) {
        terms.reserve(terms.size() + other.terms.size());
        std::move(std::begin(other.terms), std::end(other.terms), std::back_inserter(terms));
        other.terms.clear();
        return *this;
    }

    LinearCombination<V, C>& operator*=(C multiplier) {
        for (auto& term : terms) {
            term.coeff *= multiplier;
        }
        return *this;
    }

    // if V(x...) is defined
    template<typename ...X>
    auto operator()(X&&... x) const
         -> std::remove_reference_t<decltype(std::declval<V>()(std::forward<X>(x)...))> {
        auto result = zeroVector()(std::forward<X>(x)...);  <--------------- *** BAD FUNCTION CALL ***
                                                                             *************************
        for (const auto& term : terms) {
            result += term(std::forward<X>(x)...);
        }
        return result;
    }

    // if V[i] is defined
    template<typename I>
    auto operator[](I i) const -> std::remove_reference_t<decltype(std::declval<V>()[i])> {
        auto result = zeroVector()[i];
        for (const auto& term : terms) {
            result += term[i];
        }
        return result;
    }

private:
    static const V& zeroVector() {
        static V z = zero<V>();
        return z;
    }
};

这对我来说编译得很好,但我在指示的行上遇到异常(错误的函数调用)。你能帮忙吗?

【问题讨论】:

    标签: c++ c++14 variadic-templates perfect-forwarding


    【解决方案1】:

    这个函数:

    template<typename T>
    auto zero(rank<2>) -> decltype(static_cast<T>(0));
    

    赢得重载决议反对:

    template<typename T>
    auto zero(rank<0>)->std::enable_if_t<
        std::is_assignable<std::function<double(double,double)>, T>::value
        , std::function<double(double,double)>>;
    

    这是因为rank&lt;2&gt;rank&lt;0&gt; 更适合rank&lt;10&gt;{},而且:

    static_cast<std::function<double(double,double)>>(0)
    

    是一个有效的表达式。

    std::function有如下构造函数:

    function(std::nullptr_t) noexcept;
    

    这使它成为0 参数的可行选择,并且static_cast 确实考虑了构造函数。

    你最终得到std::function&lt;double(double,double)&gt; 初始化为0 (empty),当你尝试调用它时会导致异常。

    【讨论】:

    • 啊,我不知道static_cast&lt;std::function&lt;double(double,double)&gt;&gt;(0) 的事情。你是如何在脑海中安装编译器的?
    • 我颠倒了排名,我仍然遇到同样的异常......
    • @Museful It works for me
    • 是的,它也可以在 MSVC 上运行...我的代码被模板的其他实例污染,zero 尚未定义。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    相关资源
    最近更新 更多