通常采用可索引/可调用的线性组合

问题描述 投票:0回答:1

我正在尝试全局扩展并将可调用/可索引对象(在这个单词的抽象数学意义上的矢量)加在一起。

也就是说,我正在尝试采用定义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个回答
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<2>rank<10>{}更适合rank<0>,并且:

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

是有效的表达式。

即,std::function具有以下构造函数:

function(std::nullptr_t) noexcept;

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

您最终将std::function<double(double,double)>初始化为0),这会在您尝试调用它时导致异常。

© www.soinside.com 2019 - 2024. All rights reserved.