模板函数的参数没有进行任何隐式转换

时间:2011-06-21 22:19:10

标签: c++ templates c++11 template-meta-programming expression-templates

由于某些奇怪的原因,我无法在这一段代码中获取模板参数来隐式转换为兼容类型。

#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)
  • compute a + b
  • 使用a + b
  • 中的转换运算符将add<...>的结果从vec<float, 2>投射到add<...>
  • compute (a + b) + c

但它永远不会隐式演员。如果我明确地将(a + b)的结果转换为vec,则代码可以正常工作。

2 个答案:

答案 0 :(得分:5)

我将侧面解决你的实际问题,而是提出建议:不要从头开始编写所有这些复杂的样板文件,看看BoostProto,已经采取了为您处理所有棘手的细节:

  

Proto是一个用C ++构建领域特定嵌入式语言的框架。它提供了构建,类型检查,转换和执行表达式模板的工具。更具体地说,Proto提供:

     
      
  • 表达式树数据结构。
  •   
  • 为表达式提供其他行为和成员的机制。
  •   
  • 运算符重载用于从表达式构建树。
  •   
  • 用于定义表达式必须符合的语法的实用程序。
  •   
  • 用于立即执行表达式模板的可扩展机制。
  •   
  • 一组可扩展的树转换,用于表达树。
  •   

另请参阅图书馆作者的Expressive C++系列文章,这些文章或多或少都是(优秀的)深入的Boost.Proto教程。

答案 1 :(得分:2)

在模板参数推断期间,大多数转换都不会被使用。

当你调用operator+重载时,你依赖于模板参数推导:它只能在两个参数都是vec<...>类型的情况下被调用,但是当你试图调用它时,左手参数是输入add<...>。编译器无法确定您是否真的想要调用该重载(并且不允许猜测),因此错误。