使用 lambda 编译 constexpr 时出现 MSVS2017 错误 "expression did not evaluate to a constant"
MSVS2017 error "expression did not evaluate to a constant" when compile constexpr with lambda
我正在使用 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”中,我标记了出现错误的地方。它看起来像:
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 ...
上面的代码在 GCC (Link) 下编译并运行良好。
但是如何为 MSVS 修复它?
根据评论,MSVC 拒绝这一点是正确的。 pred
是一个引用,在函数体内,不知道pred
指的是什么对象。因此,常量表达式中不允许 pred(...)
,即使它实际上根本不会使用 pred
。
您可以做的是按值传递 pred
(将 const Pred &pred
更改为 Pred pred
)。然后,pred
肯定会引用一个有效的对象,这足以让 MSVC 接受调用。
我正在使用 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”中,我标记了出现错误的地方。它看起来像:
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 ...
上面的代码在 GCC (Link) 下编译并运行良好。
但是如何为 MSVS 修复它?
根据评论,MSVC 拒绝这一点是正确的。 pred
是一个引用,在函数体内,不知道pred
指的是什么对象。因此,常量表达式中不允许 pred(...)
,即使它实际上根本不会使用 pred
。
您可以做的是按值传递 pred
(将 const Pred &pred
更改为 Pred pred
)。然后,pred
肯定会引用一个有效的对象,这足以让 MSVC 接受调用。