Reputation: 720
For some strange reason, I can't get the template arguments in this one piece of code to implicitly cast to a compatible type.
#include <type_traits>
template <typename T, unsigned D>
struct vec;
template <>
struct vec<float, 2> {
typedef float scalar;
static constexpr unsigned dimension = 2;
float x, y;
float& operator[] (unsigned i) { return (&x)[i]; }
float const& operator[] (unsigned i) const { return (&x)[i]; }
};
template <typename L, typename R>
struct add;
template <typename L, typename R, unsigned D>
struct add<vec<L, D>, vec<R, D>> {
typedef vec<L, D> left_type;
typedef vec<R, D> right_type;
typedef vec<typename std::common_type<L, R>::type, D> return_type;
add(left_type l, right_type r)
: left(l),
right(r)
{}
operator return_type() const
{
return_type result;
for (unsigned i = 0; i < D; ++i)
result[i] = left[i] + right[i];
return result;
}
left_type left;
right_type right;
};
template <typename L, typename R, unsigned D>
add<vec<L, D>, vec<R, D>>
operator+(vec<L, D> const& lhs, vec<R, D> const& rhs)
{
return {lhs, rhs};
}
int main()
{
vec<float, 2> a, b, c;
vec<float, 2> result = a + b + c;
}
Fails with:
prog.cpp: In function 'int main()':
prog.cpp:55:36: error: no match for 'operator+' in 'operator+ [with L = float, R = float, unsigned int D = 2u](((const vec<float, 2u>&)((const vec<float, 2u>*)(& a))), ((const vec<float, 2u>&)((const vec<float, 2u>*)(& b)))) + c'
So if I'm correct, the compiler should see the code in the main function as this:
((a + b) + c)
a + b
a + b
from add<...>
to vec<float, 2>
using the conversion operator in add<...>
(a + b) + c
But it never does the implicit cast. If I explicitly cast the result of (a + b) to a vec, the code works fine.
Upvotes: 4
Views: 335
Reputation: 62985
I'm going to side-step your actual problem and instead make a recommendation: Rather than writing all of this complicated boilerplate from scratch, have a look at Boost.Proto, which has taken care of all the tricky details for you:
Proto is a framework for building Domain Specific Embedded Languages in C++. It provides tools for constructing, type-checking, transforming and executing expression templates. More specifically, Proto provides:
- An expression tree data structure.
- A mechanism for giving expressions additional behaviors and members.
- Operator overloads for building the tree from an expression.
- Utilities for defining the grammar to which an expression must conform.
- An extensible mechanism for immediately executing an expression template.
- An extensible set of tree transformations to apply to expression trees.
See also the library author's Expressive C++ series of articles, which more-or-less serve as an (excellent) in-depth Boost.Proto tutorial.
Upvotes: 5
Reputation: 355207
Most conversions are not used during template argument deduction.
You rely on template argument deduction when you call your operator+
overload: it is only callable where both arguments are of type vec<...>
, but when you try to call it the left-hand argument is of type add<...>
. The compiler is not able to figure out that you really mean for that overload to be called (and it isn't allowed to guess), hence the error.
Upvotes: 2