Что означает этот синтаксис "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&&
)