模板函数的参数不执行任何隐式转换

Arguments to a template function aren't doing any implicit conversion

本文关键字:执行 任何隐 转换 参数 函数      更新时间:2023-10-16

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

#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'

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

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

但它从不做隐含的演员阵容。如果我显式地将(a+b)的结果强制转换为vec,那么代码运行良好。

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

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

  • 表达式树数据结构
  • 一种赋予表达式额外行为和成员的机制
  • 运算符重载用于从表达式构建树
  • 用于定义表达式必须遵循的语法的实用程序
  • 一种可扩展的机制,用于立即执行表达式模板
  • 应用于表达式树的一组可扩展的树转换

另请参阅库作者的ExpressiveC++系列文章,这些文章或多或少是一个(优秀的)深入的Boost.Proto教程。

大多数转换在模板参数推导过程中不使用。

当您调用operator+重载时,您依赖于模板参数推导:只有当两个参数都是vec<...>类型时,它才可调用,但当您尝试调用它时,左侧参数是add<...>类型。编译器无法弄清楚您是否真的想调用该重载(而且不允许猜测),因此出现了错误。