Функция друга шаблона и вычет типа возврата

Примечание: этот вопрос очень близок кВывод типа возврата для функций-друзей в классе, но я не нашел там ответа на мою проблему.

Протестировано с 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};
}

Clang 3.4 говорит:

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

И затем указывает на то, что он считает двумя разными функциями: объявление в классе и определение вне класса.

Мой вопрос: является ли это ошибкой лягушки, или просто параметры шаблона выводятся для функции-друга, таким образом приводя к тому, что две функции не эквивалентны в некоторых случаях? И какую альтернативу вы бы предложили: сделать оператор + функцией-членом или определить оператор друга + внутри класса (что, на мой взгляд, загромождает интерфейс класса)?

Просто для вашего сведения, у меня есть реальный пример использования такого кода, где я пытаюсь обернуть класс матрицы третьей стороны, и мне нужно вывести тип возврата из-за использования шаблона выражения для отложенной оценки.

редактировать: Следующее работает (но все еще загромождает интерфейс ...)

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)

Ваш ответ на вопрос