【问题标题】:Template template parameter with mixed type and non-type variadic parameters具有混合类型和非类型可变参数的模板模板参数
【发布时间】:2019-05-16 02:54:01
【问题描述】:

我在声明以下内容时遇到了问题:

// c++17
template<typename T, typename ...Before, T v, typename ...After, template<typename ..., T, typename ...> U>
auto enum_to_type() {
    // do things with
    // U<Before..., v, After...> obj;
    // as an example:
    return U<Before..., v + 1, After...>{};
}

// demonstrate of usage

template<int v>
struct A {};

template<typename T, int v>
struct B {};

/// call enum_to_type to get next type
/// note: the following does not compile
using next_A = decltype(enum_to_type<int, 0, A>()); 
// == A<1>
template<typename T>
using next_B = decltype(enum_to_type<int, T, 0, B>()); 
// == B<1>


这个函数的目的是编写通用代码,可以利用非类型模板参数v从类模板U构造模板类,而不需要知道模板参数是如何在U中声明的.否则,必须为不同的签名编写此函数,例如U&lt;T v&gt;U&lt;typename, T v&gt;U&lt;T v, typename&gt; 等。

编辑:我想我想要的可能是不可能的。

【问题讨论】:

  • 请演示“有效”的代码。我看不到消除Before... 并使上述代码工作的方法;您仍然会尝试在参数包之后传递U,据我所知,这是不可行的。
  • @Yakk-AdamNevraumont 我刚刚用一些用例更新了这个问题
  • 尽管明确要求您提供“有效”的代码,但您未能提供。当您提供您声称“有效”的变体时,请@ping 我,该变体涉及删除Before... 而离开After...。修正错别字并删除之前,编译失败:coliru.stacked-crooked.com/a/41ccc50702c56798
  • "这个函数的目的是编写通用代码,可以利用非类型模板参数v从类模板U构造模板类,而不需要知道模板参数是如何的在 U 中声明。" 这在 C++ 中是不可能的。
  • @Yakk-AdamNevraumont 恐怕你是对的。我发现它“有效”是因为我将我的模板 U 声明为 SFAINE 的 U&lt;T, typename =void&gt;,在这种情况下它会因 U&lt;T&gt; 而失败。很抱歉造成混乱,感谢您的回答。

标签: c++ templates c++17 variadic-templates generic-programming


【解决方案1】:

可以进行一些修改:

//type container template
template<typename...>
struct types{};
//declaration
template<typename ,auto V, typename, template<typename ,decltype(V), typename...>class>
class enum_to_type;
//generic definition
template<typename First, typename ... Befors, First V, typename ... Afters, template<typename ,First, typename...>class U>
class enum_to_type<types<First, Befors...>, V, types<Afters...>, U>{
public:
    static auto go(){
        return U<types<Befors...>, V + 1, Afters...>{};
    }
};
//specialization
template<auto V, typename ... Afters, template<typename ,decltype(V), typename...>class U>
class enum_to_type<types<>, V,types<Afters...>, U>{
public:
    static auto go(){
        return U<types<>, V + 1, Afters...>{};
        //or
        //return U<types<>, V, Afters...>{};
    }
};
//Declarations and specializations for the target class templates
template<typename, int>
struct A{};

template<typename, int, typename>
struct B;
template<typename T, int V>
struct B<types<>, V, T > {};

using next_A = decltype(enum_to_type<types<int>,  0, types<>, A>::go());

template<typename T>
using next_B = decltype(enum_to_type<types<int>, 0, types<T>, B>());

template<typename, auto, typename...>
struct general_case;
template<typename ... befors, int V, typename ... afters>
struct general_case<types<befors...>, V, afters ...> {};

用法:

decltype(enum_to_type<types<>,  0, types<>, A>::go()) object_A;
decltype(enum_to_type<types<>, 0, types<int>, B>::go()) object_B;
decltype(enum_to_type<types<int, float>, 3, types<int>, general_case>::go()) object_general;

只是编译器没有办法找出前后有多少类型。这就是为什么在模板声明中通常只能采用一个参数包的原因。但它可以在专业化中处理多个参数包!

祝你好运!

【讨论】:

  • 很遗憾不能对函数模板做同样的事情,因为函数模板的非类型非变量特化是不允许的!
  • 如果您使用auto,则不再需要First
  • 虽然更改 enum_to_type 似乎可以接受,但您还可以更改输入类 AB...
  • @Jarod42 你是对的。我错过了一些观点,谢谢你提醒我。在这里,我更新了代码,现在可以了。是的,模板的接口必须改变!
  • 非常感谢您的回答。这太棒了!
猜你喜欢
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 2021-03-08
  • 1970-01-01
  • 1970-01-01
  • 2016-06-24
  • 2021-03-18
相关资源
最近更新 更多