c++ 如何将元组< >剥离回可变模板类型列表?

zzzyeukh  于 2023-11-19  发布在  其他
关注(0)|答案(5)|浏览(99)

有没有一种方法可以剥离一个std::tuple<T...>,以便让它回到T...

示例

假设vct<T...>是一个 * 预先存在的*可变类模板

using U = std::tuple<int,char,std::string>;
using X = vct<int,char,std::string>;
using Y = vct< strip<U> >;            // should be same as X

字符串

备注

我知道std::tuple_element,但我需要所有元素,以可用作T...的形式
作为参考,我找到了这个question,它是类似的,但我的需求有点简单(所以我希望有一个更简单的解决方案):我所需要的只是tuple中的类型列表-我不关心tuple示例的实际值。

e37o9pze

e37o9pze1#

template<typename>
struct strip;

template<typename ...T>
struct strip<std::tuple<T...>>
{
   using type = vct<T...>;
};

字符串
然后将其用作:

using Y = strip<U>::type;


现在YX相同。

q5lcpyga

q5lcpyga2#

不,这是不可能的。参数包是类型推导的结果,它们不能在其他上下文中产生。
你可以这样做类似于你所要求的:

template<template<typename...> class T, typename>
struct instantiate_with_arg_pack { };

template<template<typename...> class T, typename... Ts>
struct instantiate_with_arg_pack<T, std::tuple<Ts...>>
{
    using type = T<Ts...>;
};

template<typename... Ts>
struct vct { };

int main()
{
    using U = std::tuple<int,char,std::string>;
    using X = vct<int,char,std::string>;
    using Y = instantiate_with_arg_pack<vct, U>::type;
}

字符串
实际上,你不需要在元组中保存参数包:任何可变类模板都可以:

template<template<typename...> class T, typename>
struct instantiate_with_arg_pack { };

template<
    template<typename...> class T, 
    template<typename...> class U, // <===
    typename... Ts
    >
struct instantiate_with_arg_pack<T, U<Ts...>>
//                                   ^^^^^^^^
{
    using type = T<Ts...>;
};

template<typename... Ts>
struct vct { };

int main()
{
    using U = std::tuple<int,char,std::string>;
    using X = vct<int,char,std::string>;
    using Y = instantiate_with_arg_pack<vct, X>::type;
    //                                        ^

    // Won't fire
    static_assert(
        std::is_same<Y, vct<int,char,std::string>>::value, 
        "Error!");
}


这是live example

w8rqjzmb

w8rqjzmb3#

你不能直接“返回”一个参数包,所以你需要的是这样的:

template< typename... Ts >
struct vct
{ ... };

template< typename >
struct make_vct;

template< typename... Ts >
struct make_vct< std::tuple< Ts... > >
{
    typedef vct< Ts... > type;
};

字符串
和使用

using Y = make_vct< U >::type;

ia2d9nvy

ia2d9nvy4#

这里的目标是能够将参数包从一个模板的示例复制到另一个模板。我没有将其限制为tuple,因为.为什么将其限制为tuple

template<template<typename...>class Target, typename Src>
struct copy_pack_types;

template<template<typename...>class Target, template<typename...>class Src, typename... Ts>
struct copy_pack_types< Target, Src<Ts...> > {
  typedef Target<Ts...> type;
};

template<template<typename... Ts>class Target, typename Src>
using CopyPackTypes = typename copy_pack_types<Target, Src>::type;

#include <string>
#include <tuple>
template<typename... Ts> struct vct;
template<typename... Ts> struct vct2;
using U = std::tuple<int,char,std::string>;
using X = vct<int,char,std::string>;
using Y = CopyPackTypes< vct, U >;            // should be same as X
using Z = CopyPackTypes< vct2, U >;            // should be different from X

#include <iostream>
#include <type_traits>
int main() {
  std::cout << std::is_same< X, Y >::value << "\n";
  std::cout << std::is_same< Z, Y >::value << "\n";
  std::cout << std::is_same< Z, vct2<int,char,std::string> >::value << "\n";
}

字符串
输出为“1 0 1”,如预期。
CopyPackTypes接受一个目标模板和一个从参数包构造的源类型作为其唯一的参数。然后它将参数包复制到目标模板。
一个标准的技术是携带参数包,以创建一个否则没有使用的类型,如:

template<typename...>
struct types {};


它只作为一个类型列表的占位符存在。然后你可以将其中的一些传递给另一个模板,每个包不会互相“踩”。当你需要将它应用到目标模板时,你可以使用类似上面的“CopyPackTypes”来应用它。
类似的技术也用于索引包:

template<size_t...>
struct seq {};


否则无用的类型是“黑色石板”,携带参数块。

vcirk6k6

vcirk6k65#

使用C++17 std::apply

using U = std::tuple<int, char, std::string>;
using X = vct<int, char, std::string>;
using Y = vct<strip<U>>; // should be same as X

auto my_y = std::apply(
        [](auto... ts) {
            using Y = vct<decltype(ts)...>;
            return Y{};
        },
        U{});

字符串

相关问题