4

为什么会出现编译错误“无法在常量表达式中使用具有未知值的函数参数‘字段’”?

全部标记为 constexpr,我认为在编译时知道值没有任何问题。

有没有办法解决这个错误?

#include <tuple>
#include <string_view>

namespace {
  template<typename Tuple, typename F, std::size_t... Indices>
  constexpr void for_each_impl(Tuple &&tuple, F &&f, std::index_sequence<Indices...>) {
    (f(std::get<Indices>(std::forward<Tuple>(tuple))), ...);
  }

  template<typename Tuple, typename F>
  constexpr void for_each(Tuple &&tuple, F &&f) {
    const auto N = std::tuple_size<std::remove_reference_t<Tuple>>::value;
    for_each_impl(std::forward<Tuple>(tuple), std::forward<F>(f), std::make_index_sequence<N>{});
  }

  template <typename T, typename... Tuple>
  constexpr auto has_type(const std::tuple<Tuple...> &tuple) {
    return std::disjunction_v<std::is_same<T, Tuple>...>;
  }
}// namespace

template<typename A>
struct meta_field {
  constexpr meta_field(std::string_view name, A attributes)
    : name(name), attributes(attributes) {
  }

  const std::string_view name;
  const A attributes;
};

int main() {
  constexpr auto fields = std::make_tuple(meta_field("a121213", std::make_tuple(int(5))), meta_field("hello", std::make_tuple()));

  for_each(fields, [](const auto &field) {
    // why unknown value?
    if constexpr (has_type<int>(field.attributes)) {
      
    }
  });
}

大胆的链接

4

2 回答 2

3

函数参数不是 constexpr,所以你必须使用 type 来代替:

template <typename T, typename Tuple> struct has_type : std::false_type {};
template <typename T, typename... Ts> struct has_type<T, std::tuple<Ts...>> : std::disjunction<std::is_same<T, Ts>...> {};

用法类似于

for_each(fields, [](const auto &field) {
    if constexpr (has_type<int, std::decay_t<decltype(field.attributes)>>::value) {
        std::cout << std::get<int>(field.attributes) << std::endl;
    }
});

演示

于 2020-07-20T14:55:46.317 回答
0

attributes不是constexpr

您可以将其作为模板参数并static constexpr在类中进行。但是,对于要成为浮点值的非类型模板参数,您需要 C++20。

template<auto... Attributes>
struct meta_field {
  constexpr meta_field(std::string_view name)
    : name(name) {
  }
  static constexpr std::tuple<decltype(Attributes)...> attributes{Attributes...};
  const std::string_view name;
};

// ...

  constexpr auto fields = std::make_tuple(
      meta_field<5>("a121213"),
      meta_field<>("hello"));
于 2020-07-20T14:29:42.830 回答