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?