Проверка концепции с использованием библиотеки range-v3 - PullRequest
0 голосов
/ 19 марта 2019

В этом блоге post я видел, как Эрик Ниблер объяснял свое мнение о проверке концепции. Это выглядело как хороший баланс между простотой и практичностью для меня, поэтому я хотел попробовать.

Чтобы проверить себя, я придумал быструю концепцию векторных пространств. Вот код:

#include <range/v3/utility/concepts.hpp>
#include <array>
#include <algorithm>
#include <string>

struct vector_space
{
    // Valid expressions
    template<typename Field, typename Vector>
    auto requires(Field &&f, Vector &&v1, Vector &&v2) -> decltype(
        ranges::concepts::valid_expr(
            f * v1,
            v1 + v2
        ));
};

template<typename Field, typename Vector>
constexpr bool VectorSpace()
{
    return ranges::concepts::models<vector_space, Field, Vector>();
}

template<typename Field, typename Vector,
         CONCEPT_REQUIRES_(VectorSpace<Field, Vector>())>
void linear_comb(Field f1, Vector v1, Field f2, Vector v2)
{
    return (f1 * v1) + (f2 * v2);
}

template <typename T, std::size_t dim>
std::array<T, dim> operator+(std::array<T, dim> const& a1,
                             std::array<T, dim> const& a2) {
    std::array<T, dim> res;
    std::transform(a1.begin(), a1.end(), a2.begin(),
                   res.begin(),
                   [](T const& e1, T const& e2) {
                       return e1 + e2;
                   });
    return res;
}

template <typename Field, typename T, std::size_t dim>
std::array<T, dim> operator*(std::array<T, dim> const& a,
                             Field f) {
    std::array<T, dim> res;
    std::transform(a.begin(), a.end(),
                   res.begin(),
                   [f](T const& e) {
                       return f * e;
                   });
    return res;
}

template <typename Field, typename T, std::size_t dim>
std::array<T, dim> operator*(Field f, std::array<T, dim> const& a) {
    return a * f;
}

int main() {
    std::string s1 = "hello";
    std::string s2 = "world";

    std::array<float, 4> a1{1.1f, 2.2f, 3.3f, 4.4f};
    std::array<float, 4> a2{4.4f, 3.3f, 2.2f, 1.1f};
    std::array<float, 4> a3 = (3.14f * a1) + (2.71f * a2);
    linear_comb(3.14f, a1, 2.71f, a2);
} 

Как видите, я хочу проверить, что значения v1, v2 из Vector и f из Field, выражения f * v1 и v1 + v2 имеют смысл. Короче говоря, я хочу скалярное умножение и сложение векторов. Хотя я могу правильно вычислить a3 в main, функция linear_comb говорит мне, что концепция VectorSpace<Field, Vector> не выполняется. Он правильно выводит Field как float и Vector как std::array<float, 4>. Почему тогда оно не рассматривается как правильное выражение?

...