我需要计算嵌套对和元组中的类型,并提出了此代码段。但是,如果我使用gcc的declval(),则会发生以下错误:

/usr/include/c++/5.3.0/type_traits:2204:7:错误:静态断言失败:不得使用declval()!
       static_assert(__ declval_protector :: __ stop,

struct swallow
{
  template <typename ...T>
  explicit swallow(T&& ...) noexcept
  {
  }
};

template <typename C>
constexpr inline decltype(auto) declval() noexcept
{
  return ::std::move(*static_cast<C*>(nullptr));
}

template <typename T>
constexpr inline auto count_types(T const&) noexcept
{
  return 1;
}

template <typename ...A>
constexpr inline auto count_types(::std::pair<A...> const&) noexcept
{
  int r{};

  swallow{(r += count_types(declval<A>()))...};

  return r;
}

template <typename ...A>
constexpr inline auto count_types(::std::tuple<A...> const&) noexcept
{
  int r{};

  swallow{(r += count_types(declval<A>()))...};

  return r;
}

int main()
{
  ::std::cout << count_types(declval<::std::tuple<int, int, ::std::pair<int, ::std::pair<int, int>>>>());
  return 0;
}


我的问题是为什么为什么我的declval实现正确工作,而gcc却不能正常工作?接下来,我将尝试使用元模板编程来解决该问题。

编辑:这是一个修复程序,可以同时使用gccclang进行编译:

struct swallow
{
  template <typename ...T>
  constexpr explicit swallow(T&& ...) noexcept
  {
  }
};

template <typename C>
constexpr inline decltype(auto) declval() noexcept
{
  return static_cast<typename std::remove_reference<C>::type&&>(*static_cast<C*>(nullptr));
}

template <typename T>
constexpr inline auto count_types(T const&) noexcept
{
  return 1;
}

template <typename ...A>
constexpr inline auto count_types(::std::pair<A...> const&) noexcept
{
  int r{};

  swallow{(r += count_types(declval<A>()))...};

  return r;
}

template <typename ...A>
constexpr inline auto count_types(::std::tuple<A...> const&) noexcept
{
  int r{};

  swallow{(r += count_types(declval<A>()))...};

  return r;
}

int main()
{
  ::std::cout << ::std::integral_constant<int, count_types(declval<::std::tuple<int, int, ::std::pair<int, ::std::pair<int, int>>>>())>{};
  return 0;
}

最佳答案

std::declval专用于编译时逻辑。从[declval]定义为:

template <class T>
add_rvalue_reference_t<T> declval() noexcept; // as unevaluated operand


该功能没有主体。它只是在那里给你一个类型。您无法对其执行运行时操作。那不是它的目的。

declval的实现涉及在运行时显式取消引用空指针。这只是对declval的用途及其用法的误解。此外,您的declval实现不支持左值引用(例如,我可以std::declval<Foo&>()给我一个左值引用,由于要使用指向引用的指针,所以your_declval<Foo&>()格式不正确)。



编写类似内容的方法将基于类型。您仍然可以编写一个使用std::tuple<A...>并返回嵌套类型数量的函数-只是不能是运行时操作,它应该将结果编码为类型。也就是说,我们从以下内容开始:

struct adl_tag {};

template <class T>
inline auto count_types_impl(adl_tag, T const&)
    -> std::integral_constant<int, 1>;

template <class T>
using count_types = decltype(count_types_impl(adl_tag{}, std::declval<T>()));


然后只需为我们希望支持的其他类型的count_types_impl()添加其他重载即可。 adl_tag在那里,因此我们可以找到所需的所有重载。使用fold-expressions缩短答案,然后可以添加:

template <class... A>
inline auto count_types_impl(adl_tag , std::tuple<A...> const&)
    -> std::integral_constant<int, (count_types<A>::value + ...)>;

template <class A, class B>
inline auto count_types_impl(adl_tag , std::pair<A,B> const&)
    -> std::integral_constant<int, (count_types<A>::value + count_types<B>::value)>;


以便:

std::cout << count_types<std::tuple<int, std::pair<int,int>>>::value; // prints 3


请注意,绝不会评估任何内容。这些功能都没有身体!

关于c++ - 成对和元组计数嵌套类型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35817668/

10-11 19:17