连接一元参数的模板参数包
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<int>::b<>
但接受tc2<>::b<int>
。
这有意义吗?什么是可变参数描述的长度?我没有看到任何可以确定这一点的东西,所以可能是特定于实现的,但我认为可能是未定义的行为
"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<1 or more>::a<zero or more>
:
#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<>
只能接受一个 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)
【讨论】:
以上是关于连接一元参数的模板参数包的主要内容,如果未能解决你的问题,请参考以下文章