C++ 是否可以“存储”模板参数包而不扩展它?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4691657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:09:51  来源:igfitidea点击:

Is it possible to "store" a template parameter pack without expanding it?

c++templatesc++11variadic-templates

提问by Luc Touraille

I was experimenting with C++0x variadic templates when I stumbled upon this issue:

当我偶然发现这个问题时,我正在试验 C++0x 可变参数模板:

template < typename ...Args >
struct identities
{
    typedef Args type; //compile error: "parameter packs not expanded with '...'
};

//The following code just shows an example of potential use, but has no relation
//with what I am actually trying to achieve.
template < typename T >
struct convert_in_tuple
{
    typedef std::tuple< typename T::type... > type;
};

typedef convert_in_tuple< identities< int, float > >::type int_float_tuple;

GCC 4.5.0 gives me an error when I try to typedef the template parameters pack.

当我尝试 typedef 模板参数包时,GCC 4.5.0 给了我一个错误。

Basically, I would like to "store" the parameters pack in a typedef, without unpacking it. Is it possible? If not, is there some reason why this is not allowed?

基本上,我想将参数包“存储”在 typedef 中,而不将其解包。是否可以?如果没有,是否有某些原因不允许这样做?

采纳答案by GManNickG

Another approach, which is slightly more generic than Ben's, is as follows:

另一种方法比 Ben 的方法更通用,如下所示:

#include <tuple>

template <typename... Args>
struct variadic_typedef
{
    // this single type represents a collection of types,
    // as the template arguments it took to define it
};

template <typename... Args>
struct convert_in_tuple
{
    // base case, nothing special,
    // just use the arguments directly
    // however they need to be used
    typedef std::tuple<Args...> type;
};

template <typename... Args>
struct convert_in_tuple<variadic_typedef<Args...>>
{
    // expand the variadic_typedef back into
    // its arguments, via specialization
    // (doesn't rely on functionality to be provided
    // by the variadic_typedef struct itself, generic)
    typedef typename convert_in_tuple<Args...>::type type;
};

typedef variadic_typedef<int, float> myTypes;
typedef convert_in_tuple<myTypes>::type int_float_tuple;

int main()
{}

回答by Ben Voigt

I think the reason it's not allowed is that it would be messy, and you can work around it. You need to use dependency inversion and make the struct storing the parameter pack into a factory template able to apply that parameter pack to another template.

我认为它不被允许的原因是它会很乱,你可以解决它。您需要使用依赖倒置并使将参数包存储到工厂模板中的结构能够将该参数包应用于另一个模板。

Something along the lines of:

类似的东西:

template < typename ...Args >
struct identities
{
    template < template<typename ...> class T >
    struct apply
    {
        typedef T<Args...> type;
    };
};

template < template<template<typename ...> class> class T >
struct convert_in_tuple
{
    typedef typename T<std::tuple>::type type;
};

typedef convert_in_tuple< identities< int, float >::apply >::type int_float_tuple;

回答by Werner Erasmus

I've found Ben Voigt's idea very useful in my own endeavors. I've modified it slightly to make it general to not just tuples. To the readers here it might be an obvious modification, but it may be worth showing:

我发现 Ben Voigt 的想法在我自己的努力中非常有用。我稍微修改了它,使其不仅适用于元组。对于这里的读者来说,这可能是一个明显的修改,但可能值得展示:

template <template <class ... Args> class T, class ... Args>
struct TypeWithList
{
  typedef T<Args...> type;
};

template <template <class ... Args> class T, class ... Args>
struct TypeWithList<T, VariadicTypedef<Args...>>
{
  typedef typename TypeWithList<T, Args...>::type type;
};

The name TypeWithList stems from the fact that the type is now instantiated with a previous list.

名称 TypeWithList 源于这样一个事实,即该类型现在已使用先前的列表进行实例化。

回答by Hyman

This is a variation of GManNickG's neat partial specialization trick. No delegation, and you get more type safety by requiring the use of your variadic_typedef struct.

这是 GManNickG 巧妙的部分专业化技巧的变体。没有委托,并且通过要求使用 variadic_typedef 结构可以获得更多类型安全性。

#include <tuple>

template<typename... Args>
struct variadic_typedef {};

template<typename... Args>
struct convert_in_tuple {
    //Leaving this empty will cause the compiler
    //to complain if you try to access a "type" member.
    //You may also be able to do something like:
    //static_assert(std::is_same<>::value, "blah")
    //if you know something about the types.
};

template<typename... Args>
struct convert_in_tuple< variadic_typedef<Args...> > {
    //use Args normally
    typedef std::tuple<Args...> type;
};

typedef variadic_typedef<int, float> myTypes;
typedef convert_in_tuple<myTypes>::type int_float_tuple; //compiles
//typedef convert_in_tuple<int, float>::type int_float_tuple; //doesn't compile

int main() {}