У меня есть этот код:
...
#include "boost/tuple/tuple_comparison.hpp"...
template <typename ReturnType, typename... Args>
function<ReturnType(Args...)> memoize(const Args && ... args)
{
using noRef = boost::tuple<typename std::remove_reference<Args>::type...>;
static map<noRef, ReturnType, less<>> cache;
auto key = std::tie(noRef{ boost::make_tuple(args ...) });
auto it = cache.lower_bound(key);
ReturnType result;
if (it->first == key) { ...
Но когда я пытаюсь скомпилировать его, я получаю эту ошибку:
error C2678: binary '==': no operator found which takes a left-hand operand of type 'const noRef' (or there is no acceptable conversion)
Почему это происходит, так как noRef
это псевдоним для boost::tuple
а также tuple_comparison
должен управлять этим делом?
ОШИБКА НАЙДЕНА, НЕ ЗНАЮ, КАК ЕГО РЕШИТЬ:
Похоже, ошибка была в std::tie
операция. Так что переписать это как:
auto key = noRef{ boost::make_tuple(args ...) };
Работает отлично. Проблема в том, что это решение неэффективно, так как key
является потенциально дорогой копией всего кортежа, при использовании tie
это кортеж ссылок (гораздо меньше). Итак, как я могу взять ссылку на it->first
кортеж? Должен ли я использовать то же самое tie
трюк?
Единственная причина, по которой эта строка компилируется — это расширение MSVC Evil Extension.TM который позволяет неконстантным ссылкам lvalue связываться с временными файлами:
auto key = std::tie(noRef{ boost::make_tuple(args ...) });
Это должно быть просто
auto key = boost::tie(args...);
который создает boost::tuple
ссылок, которые будут использоваться для поиска позже.
Также, как отмечено в комментариях, if
проверка должна проверить it != cache.end()
сначала, прежде чем пытаться разыменовать его (спасибо!).
В заключение, const Args && ...
не имеет особого смысла, так как вряд ли кто-то захочет принять постоянные значения. Это, вероятно, должно быть либо const Args&...
или же Args&&...
,
Других решений пока нет …