合法的交换运营商的模板实施

Template implementation for commutative operators, legal?

本文关键字:运营商 交换      更新时间:2023-10-16

我试图为我的一个类实现一个交换添加操作员:

struct mytype
{
    constexpr mytype(othertype const &);
    constexpr mytype operator+(othertype const &rhs) const;
};
template<typename T>
constexpr auto operator+(T const &lhs, mytype const &rhs) -> decltype(rhs + lhs)
{
    return rhs + lhs;
}

的想法是,只要右侧是 mytype

这与ICC和Visual Studio一起使用,并进入无尽的递归,解决了GCC和Clang上的decltype(当达到最大模板深度时终止)。

我可以看到,无尽的递归实际上可能更正确,如错误报告中所述:在进行过载分辨率之前需要专业化(因为它是过载分辨率的输入)。

另一方面,商业编译器以某种方式管理(无论是偶然还是故意是有争议的)。

这里的正确行为是什么?

是否有可能避免指定operator+应该是可交换的类的完整列表?

可编译的示例:

struct othertype {};
struct mytype
{
    constexpr mytype() : value(1) { }
    constexpr mytype(int v) : value(v) { }
    constexpr mytype(othertype const &o) : value(2) { }     // 1
    constexpr mytype operator+(mytype const &rhs) const
    {
        return mytype(value + rhs.value);
    }
    constexpr mytype operator+(othertype const &rhs) const  // 2
    {
        return mytype(value + 2);
    }
    int value;
};
template<typename T>
constexpr auto operator+(T const &lhs, mytype const &rhs) -> decltype(rhs + lhs)
{
    return rhs + lhs;
}
void test()
{
    constexpr mytype mine;
    constexpr othertype other;
    constexpr auto result = other + mine;
    static_assert(result.value == 3);
}

当删除转换// 1时,问题消失了,这在我的用例中无济于事。单独的添加操作员// 2不足以帮助解决decltype:重载分辨率应该已经选择了,但是问题发生在过载分辨率之前发生。

无限递归在专门为T = othertype的模板:将othertype转换为mytype的模板之后提供了两侧的mytype的添加表达式,这可以通过模板再次解决(即使存在非template)。

您可能会用Sfinae限制模板丢弃operator+<mytype>(mytype const &lhs, mytype const &rhs)

template<typename T, typename std::enable_if<!std::is_same<T, mytype>::value, int>::type = 0>
constexpr auto operator+(T const &lhs, mytype const &rhs) -> decltype(rhs + lhs)
{
    return rhs + lhs;
}

demo