4

出于某种奇怪的原因,我无法将这段代码中的模板参数隐式转换为兼容类型。

#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;
}

失败:

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'

因此,如果我是正确的,编译器应该会看到 main 函数中的代码如下:

  • ((a + b) + c)
  • 计算a + b
  • 使用转换运算符将a + bfromadd<...>的结果转换为vec<float, 2>add<...>
  • 计算(a + b) + c

但它从不进行隐式转换。如果我将 (a + b) 的结果显式转换为 vec,则代码可以正常工作。

4

2 回答 2

5

我将回避您的实际问题,而是提出建议:与其从头开始编写所有这些复杂的样板,不如看看BoostProto,它为您处理了所有棘手的细节:

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.

于 2011-06-22T00:00:38.093 回答
2

在模板参数推导期间不使用大多数转换。

当你调用你的operator+重载时,你依赖于模板参数推导:它只能在两个参数都是 type 的情况下调用vec<...>,但是当你尝试调用它时,左边的参数是 type add<...>。编译器无法弄清楚您是否真的意味着要调用该重载(并且不允许猜测),因此会出现错误。

于 2011-06-21T22:30:01.763 回答