模板友元函数和返回类型推导

Template friend function and return type deduction

本文关键字:返回类型 函数 友元      更新时间:2023-10-16

注意:这个问题非常接近类友元函数的返回类型推导,但我在那里没有找到问题的答案。

使用 clang 3.4 和 std=c++

1y 和 clang 3.5 测试 std=c++14 和 std=c++1z 进行测试

此代码编译:

#include <iostream>
template<class T>
class MyClass {
    public:
        MyClass(T const& a) : impl(a) {}
        template<class T0, class T1> friend auto
        // requires operator+(T0,T1) exists
        operator+(MyClass<T0> const& a, MyClass<T1> const& b)
        {
            return MyClass<decltype(a.impl+b.impl)>{a.impl + b.impl};
        }
        T getImpl() const { return impl; }
    private:
        T impl;
};
int main() {
    MyClass<int> x(2);
    MyClass<long> y(2);
    auto z = x+y;
    std::cout << z.getImpl() << "n";
}

现在,如果我在类之外定义 operator+,它不再编译:

template<class T>
class MyClass {
    public:
        MyClass(T const& a) : impl(a) {}
        template<class T0, class T1> friend auto
        operator+(MyClass<T0> const& a, MyClass<T1> const& b);
        T getImpl() const { return impl; }
    private:
        T impl;
};
template<class T0, class T1> auto
operator+(MyClass<T0> const& a, MyClass<T1> const& b)
{
    return MyClass<decltype(a.impl+b.impl)>{a.impl + b.impl};
}

叮当 3.4 说:

error: use of overloaded operator '+' is ambiguous (with operand types MyClass<int> and MyClass<long>)

然后指出它认为是两个不同的函数:类中的声明和类外的定义。

我的问题是:这是一个叮当错误,还是只是为朋友函数推断出模板参数,从而导致两个函数在某些情况下不等效?你会建议什么替代方案:使 operator+ 成为成员函数,或者在类中定义 friend operator+(在我看来,这会使类接口混乱)?

仅供您参考,我有一个此类代码的真实用例,我尝试包装第三方矩阵类,并且由于使用表达式模板进行惰性计算,我需要返回类型推断。

编辑:以下内容确实有效(但仍然使界面混乱...

template<typename T>
class MyClass
{
    T impl;
public:
    explicit MyClass(T a) : impl(std::move(a)) { }
    T const& getImpl() const { return impl; }
    template<typename T0, typename T1>
    friend auto operator +(MyClass<T0> const& a, MyClass<T1> const& b) -> MyClass<decltype(a.impl + b.impl)>;
};
template<typename T0, typename T1>
auto operator +(MyClass<T0> const& a, MyClass<T1> const& b) -> MyClass<decltype(a.impl + b.impl)>
{
    return MyClass<decltype(a.impl + b.impl)>(a.impl + b.impl);
}

编辑:看看评论部分,这是 GCC 4.8.2 和 4.9 中的一个错误

GCC 错误代码:

prog.cpp:10:61:错误:非静态数据成员声明为"auto" operator+(MyClass const& a, MyClass const& b) ^ prog.cpp: 在函数 'int main()' 中: prog.cpp:25:15: error: no match 对于"运算符+"(操作数类型为"MyClass"和"MyClass") 自动 z = x+y; ^