AeroSun
AeroSun

Reputation: 2571

MSVS2017 error "expression did not evaluate to a constant" when compile constexpr with lambda

I am using MSVS c++17 and the code below can`t be compiled:

#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);
}

In the function "makeIndices" I marked place where error appears. Its looks like:

error C2131: expression did not evaluate to a constant

note: failure was caused by a read of a variable outside its lifetime

note: see usage of 'pred'

note: see reference to function template instantiation 'auto makeIndices<8,Pred,0,>(const Pred &)' being compiled ...

The code above compiled and worked fine with GCC (Link).

But how it could be fixed for MSVS?

Upvotes: 0

Views: 4669

Answers (1)

user743382
user743382

Reputation:

Per the comments, MSVC is right to reject this. pred is a reference, and inside the function body, it is unknown what object pred refers to. Therefore, pred(...) is not allowed in constant expressions, even if it wouldn't actually use pred at all.

What you can do though, is pass pred by value (change const Pred &pred to Pred pred). Then, pred will assuredly refer to a valid object, and that is enough to get MSVC to accept the call.

Upvotes: 1

Related Questions