【问题标题】:A generic type trait to non-recursively get the last type of a variadic template? [duplicate]非递归获取可变参数模板的最后一种类型的泛型类型特征? [复制]
【发布时间】:2020-10-21 08:07:06
【问题描述】:

注意:

我关心的是编译速度。

我假设递归类型特征通常比替代方法慢(如果可能)。如果我对此有误,请告诉我。


我们可以在不递归的情况下访问可变参数列表前面的类型,如下所示:

#include <iostream>
#include <type_traits>

template <typename T>
struct this_type
{
    using type = T;
};

template <typename T1, typename ...>
struct front : this_type<T1> {};

template <typename ... Ts>
using front_t = typename front<Ts...>::type;

template <typename ... Ts>
void Foo ()
{
    std::cout << std::is_same_v<front_t<Ts...>, int> << std::endl;
}

int main ()
{
    Foo<int, char, bool>();
}

但是,我想不出一种 通用 方法来访问返回类型而不使用递归。直觉上我想做这样的事情:

template <typename ...>
struct pack;

template <typename ...>
struct back;

template <typename Tn, typename ... Ts>
struct back <pack<Ts..., Tn>> : this_type<Tn> {};

template <typename ... Ts>
using back_t = typename back<pack<Ts...>>::type;

...但可变参数模板需要是特化中的最后一个参数。

我们可以使用一些代码膨胀来管理一定数量的访问元素。例如,3:

template <typename ...>
struct back;

template <typename T1>
struct back <T1> : this_type<T1> {};

template <typename T1, typename T2>
struct back <T1, T2> : this_type<T2> {};

template <typename T1, typename T2, typename T3>
struct back <T1, T2, T3> : this_type<T3> {};

template <typename ... Ts>
using back_t = typename back<Ts...>::type;

template <typename ... Ts>
void Foo ()
{
    std::cout << std::is_same_v<back_t<Ts...>, bool> << std::endl;
}

int main ()
{
    Foo<int, char, bool>();
}

...但是有没有办法在没有递归的情况下通用地做到这一点?


动机:

通常我们可以改变解决问题的方式,以便从可变参数列表的前面附近访问,但有时从后面访问是不可避免的。如果有一些我没有利用的语言特性,我不想为编译器创建无用的工作。

【问题讨论】:

  • 据我所知,这是一个骗局。如果我遗漏了什么,请告诉我,我会投票重新开放。
  • @cigen,你是对的。这个问题也有一个有希望的答案。谢谢!

标签: c++ c++17 variadic-templates template-meta-programming typetraits


【解决方案1】:

我会利用 std::tuple 来完成大部分繁重的工作。

template<typename... Ts>
using back_t = std::tuple_element_t<std::tuple<Ts...>, sizeof...(Ts) - 1>;

【讨论】:

  • 嗯。这或多或少是我用我自己的版本做的一个元组(doh!)。然而,这并不能完全回答这个问题。我刚刚看了cppref,他们的“可能的实现”使用了头优先递归,所以在后面推断类型可能很慢。 (en.cppreference.com/w/cpp/utility/tuple/tuple_element)
  • @Elliott 你可以搜索你的供应商的&lt;tuple&gt;,看看他们实际做了什么。出于某种原因,它被称为“可能的实施”而不是“强制实施”
  • 看看 GCC 10,它也是递归的。这也没有相当让我相信这是不可能的,因为如果可以从后面访问,那么tuple_element_t 仍然没有'没有强烈的动机使用它,因为它的用户很可能从前面访问(你可以使用一些条件,如果index &gt; size/2然后从后面访问,但这可能不值得从速度增益考虑到小的额外开销,尤其是在小的可变参数中)。
  • 所以我的问题被标记为重复-那里的一些答案显示了如何在c++11 中获得O(log(n)) 递归,在c++17 中获得O(1),但我认为我应该指出std::tuple_elementgccclang 中都是通过递归实现的(我还没有检查msvc),因此在修复之前应该避免使用。它非常慢..见Julius' 答案:stackoverflow.com/a/47442393/8658157
  • 仅供参考,我已经在 msvc 上测试了 std::tuple_element_t,它也是递归的 - 更重要的是,它比替代方案慢得多。
猜你喜欢
  • 2017-03-18
  • 2011-09-08
  • 2023-03-22
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多