连接一元参数的模板参数包

Posted

技术标签:

【中文标题】连接一元参数的模板参数包【英文标题】:Concatenating template parameter packs for a unary argument 【发布时间】:2016-06-20 13:19:18 【问题描述】:

尽管std::add_pointer 是一元的,但以下代码被 GCC 7.0.0 (20160608) 和 Clang 3.9.0 接受:

template <typename ...Ts>
struct tc1 
  using a = std::add_pointer<Ts...>;
;

但是,虽然以下代码被 Clang 接受,但被 GCC 拒绝:

template <typename ...Ts>
struct tc2 
  template <typename ...Us>
  using b = std::add_pointer<Ts...,Us...>;
;

这是有效的 C++ 吗?从语法上讲,我可以想象当包是空的时逗号是一个问题,但大概在其他场合它被省略了;例如,std::common_type 接受零个或多个参数,以下对任一编译器都没有问题:

template <typename ...Ts>
struct tc3 
  template <typename ...Us>
  using c = std::common_type<Ts...,Us...>;
;

【问题讨论】:

注意:clang 拒绝实例化如tc2&lt;int&gt;::b&lt;&gt; 但接受tc2&lt;&gt;::b&lt;int&gt; 这有意义吗?什么是可变参数描述的长度?我没有看到任何可以确定这一点的东西,所以可能是特定于实现的,但我认为可能是未定义的行为 "The program is ill-formed, no diagnostic required, if: [...] every valid specialization of a variadic template requires an empty template parameter pack". 【参考方案1】:

您可以在 GCC 和 Clang 上将此代码用于任意数量的模板参数 tc3&lt;1 or more&gt;::a&lt;zero or more&gt;

#include <type_traits>

struct A 
    template<typename ...Args> A(Args ... args) 
;

template <typename T, typename ...Ts>
struct tc3 
  template <typename ...Us>
  using c = std::add_pointer<T(Ts...,Us...)>;
;

int main() 
    typedef tc3<A, int, float>::template c<unsigned, double>::type  ptr;// A(*)(int,float,unsigned,double)
    typedef tc3<A>::template c<>::type ptr2;                // A(*)()
    typedef tc3<bool>::template c<int, int>::type ptr3;     // bool(*)(int,int)
    typedef std::add_pointer<bool(int, int)>::type ptr4;    // bool(*)(int,int)

    return 0;

GCC 7.0.0:http://melpon.org/wandbox/permlink/m7Re0kFevMjalv6s Clang 4.0.0:http://melpon.org/wandbox/permlink/mXDtQRN7COxhtLN8

但是,当 Clang 接受以下代码时,它被拒绝了 通过海湾合作委员会:

Clang 仅在实例化之前接受以下代码,但在出现错误之后:

template <typename ...Ts>
struct tc2 
  template <typename ...Us>
  using b = std::add_pointer<Ts...,Us...>;
;
错误 Clang 4.0:http://melpon.org/wandbox/permlink/vpBCJHlvWk1ai1ny 错误 GCC 7.0.0:http://melpon.org/wandbox/permlink/a1rRfDI5zcUz3nau

std::add_pointer&lt;&gt; 只能接受一个 tamplte 参数:http://en.cppreference.com/w/cpp/types/add_pointer

template< class T >
struct add_pointer;

它只能在内部 namespace 详细信息或其他一些参数中使用多个参数:

可能的实施:

namespace detail 
    template< class T, bool is_function_type = false >
    struct add_pointer 
        using type = typename std::remove_reference<T>::type*;
    ;

    template< class T >
    struct add_pointer<T, true> 
        using type = T;
    ;

    template< class T, class... Args >
    struct add_pointer<T(Args...), true> 
        using type = T(*)(Args...);
    ;

    template< class T, class... Args >
    struct add_pointer<T(Args..., ...), true> 
        using type = T(*)(Args..., ...);
    ;

 // namespace detail

template< class T >
struct add_pointer : detail::add_pointer<T, std::is_function<T>::value> ;

这样做是为了支持此代码:

typedef std::add_pointer<bool(int, int)>::type ptr4;    // bool(*)(int,int)

【讨论】:

以上是关于连接一元参数的模板参数包的主要内容,如果未能解决你的问题,请参考以下文章

函数模板参数包后跟模板参数和特化

第21课 可变参数模板_展开参数包

如何对可变参数模板函数的异构参数包进行通用计算?

C++11 ——— 可变参数模板

C++11 ——— 可变参数模板

如何在可变参数模板中有多个参数包?