Ошибка MSVS2017 "выражение не оценивается как константа" при компиляции constexpr с помощью лямбды
Я использую MSVS C++17 и приведенный ниже код не может быть скомпилирован:
#include <type_traits>
#include <tuple>
using namespace std;
template <size_t Size, class Pred, size_t idx=0, size_t... pass>
constexpr auto makeIndices(const Pred &pred)
{
if constexpr(idx >= Size)
{
return index_sequence<pass...>();
}
else if constexpr(pred(integral_constant<size_t, idx>())) //<-- HERE!!!!
{
return makeIndices<Size, Pred, idx+1, pass..., idx>(pred);
}
else
{
return makeIndices<Size, Pred, idx+1, pass...>(pred);
}
}
template <class Tuple, size_t... I>
constexpr auto extract(Tuple&&v, index_sequence<I...> = index_sequence<I...>())
{
return tuple<tuple_element_t<I, decay_t<Tuple>>...>(get<I>(forward<Tuple>(v))...);
}
template <class Tuple, class Pred>
constexpr auto extract(Tuple&&v, const Pred &pred)
{
return extract(std::forward<Tuple>(v), makeIndices<tuple_size_v<decay_t<Tuple>>>(pred));
}
template <class Target, class Tuple>
constexpr auto del(Tuple &&v)
{
return extract(std::forward<Tuple>(v), [](auto idx)
{
return !is_same_v<Target, tuple_element_t<idx(), decay_t<Tuple>>>;
});
}
void MyFunc()
{
auto src = make_tuple("one", 1, "two", 2, "three", 3, "fourty", 40);
del<int>(src);
}
В функции "makeIndices" я отметил место, где появляется ошибка. Это выглядит так:
ошибка C2131: выражение не было константой
примечание: сбой был вызван чтением переменной вне ее времени жизни
примечание: смотрите использование 'pred'
примечание: см. ссылку на экземпляр шаблона функции 'auto makeIndices<8,Pred,0,>(const Pred &)', который компилируется...
Приведенный выше код скомпилирован и прекрасно работает с GCC ( Link).
Но как это можно исправить для MSVS?
1 ответ
Согласно комментариям, MSVC прав, чтобы отклонить это. pred
является ссылкой, а внутри тела функции неизвестно, какой объект pred
относится к. Следовательно, pred(...)
не допускается в константных выражениях, даже если он на самом деле не использует pred
совсем.
Что вы можете сделать, это пройти pred
по значению (изменение const Pred &pred
в Pred pred
). Затем, pred
будет обязательно ссылаться на действительный объект, и этого достаточно, чтобы MSVC принял вызов.