一般采用 indexibles/callables 的线性组合
Generically taking linear combinations of indexibles/callables
我正在尝试全局缩放 callable/indexible 个对象(抽象数学意义上的向量)并将它们加在一起。
也就是说,我正在尝试采用定义 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
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;
}
};
这对我来说编译得很好,但我在指示的行上遇到异常(错误的函数调用)。你能帮忙吗?
这个函数:
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<0>
更适合 rank<10>{}
,并且:
static_cast<std::function<double(double,double)>>(0)
是一个有效的表达式。
也就是说,std::function
具有以下构造函数:
function(std::nullptr_t) noexcept;
这使得它成为 0
论点的可行选择,并且 static_cast
确实考虑了构造函数。
你最终得到 std::function<double(double,double)>
初始化为 0
(empty),当你试图调用它时会导致异常。
我正在尝试全局缩放 callable/indexible 个对象(抽象数学意义上的向量)并将它们加在一起。
也就是说,我正在尝试采用定义 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
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;
}
};
这对我来说编译得很好,但我在指示的行上遇到异常(错误的函数调用)。你能帮忙吗?
这个函数:
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<0>
更适合 rank<10>{}
,并且:
static_cast<std::function<double(double,double)>>(0)
是一个有效的表达式。
也就是说,std::function
具有以下构造函数:
function(std::nullptr_t) noexcept;
这使得它成为 0
论点的可行选择,并且 static_cast
确实考虑了构造函数。
你最终得到 std::function<double(double,double)>
初始化为 0
(empty),当你试图调用它时会导致异常。