Что означает этот синтаксис "decltype (* (T *) (0) ** (U *) (0))"?

Я читаю этот вопрос по часто задаваемому вопросу isocpp, этот вопрос объясняет, как написать возвращаемый тип для ???

template<class T, class U>
??? mul(T x, U y)
{
return x*y;
}

Я понимаю, что простой способ - написать auto mul(T x, U y) -> decltype(x*y), однако вопрос также дает другой путь, который заключается в замене ??? на decltype(*(T*)(0)**(U*)(0)). Но я не совсем понимаю, что действительно делает этот decltype(*(T*)(0)**(U*)(0)), кажется, что он объявляет временный указатель T* и инициализирует его нулем, а затем разыгрывает указатель, а затем умножается на тот же экземпляр для типа U, правильно ли я понимаю?

Но зачем использовать указатели? Я думаю, что decltype(T(0)*U(0)) или decltype(T{0}*U{0}) также должны работать.

Ответы

Ответ 1

decltype(*(T*)(0)**(U*)(0))

Разделите его:

(T*)(0) //cast a null pointer to a T*
*(T*)(0) //dereference, giving a T

(U*)(0) //cast a null pointer to a U*
*(U*)(0) //dereference, giving a U

(*(T*)(0)) * (*(U*)(0)) //the result of multiplying a U and a T

decltype(T(0)*U(0)) эквивалентен только в том случае, если T и U имеют конструкторы, принимающие один int (или то, что может быть неявно преобразовано из целочисленного литерала).

Стандартная библиотека уже имеет std::declval, чтобы сделать это более чистым способом:

decltype(std::declval<T>() * std::declval<U>())

Ответ 2

это действительно ошибка.

в вашем решении вы в основном предполагаете, что конструктор может получить 0 в качестве аргумента, и это может быть не так.

фрагмент в основном отличает NULL к некоторому указателю объекта T, затем вытаскивает T с помощью оператора *, теперь мы оставили в основном decltype({T object}*{U object}), он предполагает, что во время компиляции decltype будет заменен реальным типом, и во время выполнения не будет указателей. но этот код очень уродлив и не поддерживается.

лучшим решением является использование С++ 11 std::result_of:
typename std::result_of<declval<T>()*declval<U>()>::type

declval делает что-то похожее на *(T*)(0) только он возвращает ссылку на значение r (значение T&&)