0

Using variadic templates we can write a function add, which takes any number of input parameters, and then returns a single Expression (to be lazily evaluated). When called for a specific index i, this expression sums all elements at i for all the input vectors in one go.

#include <tuple>
#include <array>

template<class ... Ts>
struct Expression
{
    Expression(const Ts& ... args)
        : args(args ...) { }

    auto operator[](const size_t& i) const
    {
        return std::apply([i](const auto& ... v) { return (v[i] + ...); }, args);
    }

    const std::tuple<const Ts& ...> args;
};

template<class ... Ts>
Expression<Ts ...> add(const Ts& ... args)
{
    return Expression(args ...);
}

int main()
{
    std::array v1{ 2,5,4 }, v2{ 9,4,2 }, v3{ 4,2,8 };

    auto result = add(v1, v2, v3);
    return result[2];  // returns 14
}

All this seems very nice and neat, but is it possible to overload an actual operator, i.e. write the following:

template<class ... Ts>
Expression<Ts ...> operator+(const Ts& ... args)
{
    return Expression(args ...);
}

int main()
{
    std::array v1{ 2,5,4 }, v2{ 9,4,2 }, v3{ 4,2,8 };

    auto result = v1 + v2 + v3; // Compiler Error
    return result[2];
}

Unfortunately, the second code using v1 + v2 + v3 results in compile errors:

  • VS 2019: Fatal Error C1001, An internal error has occurred in the compiler.
  • GCC 8.3.0: 'Expression<Ts ...> operator+(const Ts& ...)' must have an argument of class or enumerated type

Are there ways to make this work?

Phil-ZXX
  • 2,359
  • 2
  • 28
  • 40
  • 1
    [Tangent] Be careful using `Expression(const Ts& ... args) : args(args ...) { } ... const std::tuple args;`. As is the constructor will accept temporaries and you'll be left with a tuple of references that are dangling. Adding `Expression(const Ts&& ... args) = delete;` will stop that. – NathanOliver Oct 22 '19 at 20:58
  • @NathanOliver Oh that's very useful to know. Thanks! – Phil-ZXX Oct 22 '19 at 20:59
  • 1
    tl;dr: you can't have a variadic operator function - you have to make your `operator+` binary. – Barry Oct 22 '19 at 21:12

0 Answers0