Template friend function and return type deduction

偶尔善良 提交于 2019-12-04 19:05:56

问题


Note: This question is really close to Return type deduction for in-class friend functions, but I did not find the answer to my problem there.

Tested with clang 3.4 with std=c++1y and clang 3.5 with std=c++14 and std=c++1z

This code compiles:

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

Now if I define operator+ outside of the class, it does not compile anymore:

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

Clang 3.4 says:

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

And then points at what it believes to be two different functions: the declaration in the class and the definition outside the class.

My question is: is it a clang bug, or just that template parameters are deduced for a friend function thus leading the two functions not being equivalent is some cases ? And what alternative would you suggest: make operator+ a member function, or define friend operator+ inside the class (which would in my opinion clutter the class interface) ?

Just for your information, I have a real use case of such code, where I try to wrap a third -party matrix class and I need return type deduction because of the use of expression template for lazy evaluation.

Edit: The following does work (but still clutters the interface...)

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

回答1:


edit: look at the comments section, it's a bug in gcc 4.8.2 and 4.9

Gcc error code:

prog.cpp:10:61: error: non-static data member declared 'auto' operator+(MyClass const& a, MyClass const& b) ^ prog.cpp: In function 'int main()': prog.cpp:25:15: error: no match for 'operator+' (operand types are 'MyClass' and 'MyClass') auto z = x+y; ^



来源:https://stackoverflow.com/questions/27946528/template-friend-function-and-return-type-deduction

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!