Я пытался реализовать оператор коммутативного сложения для одного из моих классов:
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 и идет в бесконечную рекурсию, разрешая decltype
для gcc и clang (прекращается, когда достигается максимальная глубина шаблона).
Я вижу, что бесконечная рекурсия на самом деле может быть более правильной, как объяснено в отчете об ошибке : специализация необходима перед разрешением перегрузки (поскольку она является входом дляразрешение перегрузки).
1013 * с другой стороны, коммерческие компиляторы как-то управлять (случайно ли или с целью, вероятно, спорно). 1015 * Что такое правильное поведение здесь? 1017 *Можно ли избежать указания полного списка классов, для которых
operator+
должен быть коммутативным?
Компилируемый экзаменple:
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
с обеих сторон, которое снова может быть разрешено с помощью шаблона (даже если существует не шаблон).