0xbadf00d
0xbadf00d

Reputation: 18188

Determine the correct size type for the result of a binary operation between two vector types or one vector type and a scalar type

Please consider the following code snippet:

template<class E>
class vector_expression {};

template<class Tuple>
class vector
    : public vector_expression<vector<Tuple>>
{
public:
    using value_type = typename Tuple::value_type;
    using size_type = typename Tuple::size_type;
};

namespace detail
{
    template<class E>
    constexpr bool is_vector_expression_v = std::is_base_of_v<vector_expression<std::decay_t<E>>, std::decay_t<E>>;

    template<class E, class = void>
    struct value_type { using type = std::decay_t<E>; };
    template<class E>
    struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> { using type = typename std::decay_t<E>::value_type; };

    template<class E>
    using value_type_t = typename value_type<E>::type;

    template<class E1, class E2, class BinaryOperation>
    class vector_binary_operation
    {
    public:
        using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>, value_type_t<E2>)>;
    };
}

E1 and E2 might be either a type derived from vector_expression or any type used as the value_type of a vector.

The vector type corresponding to the result of a vector_binary_operation needs to be chosen with care. It makes perfectly sense that its value_type equals the type of the result of the invoked BinaryOperation.

However, the correct size_type is harder to deduce. Here's what I want to do:

It won't happen that E1 and E2 are both no vector_expressions. However, (take that as a secondary question) should I add a class = std::enable_if_t<is_vector_expression_v<E1> || is_vector_expression_v<E2>> to the template parameter list of vector_binary_operation?

The main question is: How can I define size_type as described above?

Upvotes: 1

Views: 82

Answers (2)

MSalters
MSalters

Reputation: 179917

Generally I find that in such cases, it may often be easiest to just define a set of overloads auto Foo(E1,E2) -> ResultType to do the actual operation, and then set vector_binary_operation::size_type = decltype(Foo(E1,E2)).

In your particular case, you'd have three overloads: for E1, E2 or both being a vector_expression.

In this particular case I see an alternative. Introduce a helper template<typename T> class sizer { const int max = 0; } with a specialization template<typename T> class sizer<vector_expression<T>> { const int max = std::numeric_limits<typename std::decay_t<E1>::size_type>::max() ; }.

The idea behind this is simple. Your general expression compares two properties from two vector expressions, and picks the type for which the property is greatest. By defining this property to be zero for all other types, all other types rank below your vector_typs and won't get chosen.

Upvotes: 1

Jarod42
Jarod42

Reputation: 217478

A way to do that is with additional traits or enrich your current traits:

You may make a traits which give sizeof(E1::size_type) for vector_expression and 0 for

template<class E, class = void>
struct value_type {
    using type = std::decay_t<E>;
    using size_type = char; // or better some dummy type
    static constexpr std::size_t size = 0; // To be the minimal size
};
template<class E>
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> {
    using type = typename std::decay_t<E>::value_type;
    using size_type = typename std::decay_t<E>::size_type;
    static constexpr std::size_t size = std::numeric_limits<size_type>::max();
};

And then

template<class E1, class E2, class BinaryOperation>
class vector_binary_operation
{
public:
    using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>,
                                                        value_type_t<E2>)>;
    using size_type = std::conditional_t<(value_type<E1>::size < value_type<E2>::size),
                                         typename value_type <E1>::size_type,
                                         typename value_type <E2>::size_type>>>;
};

Upvotes: 2

Related Questions