检查所有可变参数模板参数的traits [英] Check traits for all variadic template arguments
问题描述
背景:我创建了以下类 C
,其构造函数应该 N
B&
的变量:
都是
class B
{
A * getA();
};
template< size_t N>
class C
{
public:
template< typename ... Args>
inline C(Args& ... args):
member {args.getA()...}
{}
private:
std :: array< ; A *,N>会员;
};问题:我的问题是如何约束变量<$ c $ <$> $ <$> $ <$> ArgsB
?
解决方案:我想定义一个谓词,如:
template< typename T,size_t N,typename 。Args>
struct is_range_of:
std :: true_type //如果Args是N的副本T
std :: false_type //否则
{};
然后重新定义我的构造函数:
template< typename ... Args,
typename = typename std :: enable_if< is_range_of_< B,N,Args ...> :: value> :: type
>
inline C(Args& ... args);
我已经看到这个帖子的一个可能的解决方案: http://stackoverflow.com/a/11414631 ,它定义了一个通用的
check_all
谓词:模板< template< typename> class Trait,typename ... Args>
,我调用
struct check_all:
std :: false_type
{};
template< template< typename> class Trait>
struct check_all< Trait> :
std :: true_type
{};
template< template< typename> class Trait,typename T,typename ... Args>
struct check_all< Trait,T,Args ...> :
std :: integral_constant< bool,Trait< T> :: value&& check_all< Trait,Args ...> :: value>
{};因此,我可以这样写:
pre>template< typename T,size_t N,typename ... Args>
,因为我需要以某种方式绑定
struct is_range_of:
std :: integral_constant< bool,
sizeof ...(Args)== N&
check_all< Trait,Args ...> :: value
>
{};问题1:我不知道如何定义<$> $ c $ c> Traitstd :: is_same
与B
作为第一个参数。在我的情况下是否有使用通用check_all
的方法,或者是C ++的当前语法不兼容?
问题2:我的构造函数还应接受
B
的派生类(通过引用B
),是模板参数扣除的问题吗?恐怕如果我使用像std :: is_base_of
这样的谓词,我会得到每个参数的构造函数的不同的实例化,这可能会增加编译代码的大小。 ..
编辑:例如,我有
B1
和<$ c $从B
继承的B2 C 2(b1,b1)
和C 2(b1,b2)
在我的代码中,将创建两个实例(C 2> B1,B1>
和C 2 :: C< B1,B2>
)?我只想要C 2> :: C< B,B>
的实例。解决方案将
all_true
定义为template< bool ...> struct bool_pack;
template< bool ... v>
using all_true = std :: is_same< bool_pack< true,v ...>,bool_pack< v ...,true>>
并将您的构造函数重写为
//检查兑换为B& ;;也可以使用事实getA()是非const
template< typename ... Args,
typename = std :: enable_if_t< all_true< std :: is_convertible< Args& {} ...> {}>
C(Args& ... args):
member {args.getA()...}
{}
恐怕如果我使用std :: is_base_of这样的谓词,我会得到
a不同的构造函数实例化设置
参数,这可能会增加编译代码大小...
enable_if_t< ;
将始终产生类型void
(仅给出一个模板参数),因此不能is_base_of
s故障。但是,当Args
有不同的类型,即参数的类型是不同的,则随后将实例化不同的专门化。
如果你希望构造函数采用
N
参数,您可以使用一个更简单的方法。定义模板< std :: size_t,typename T&
using ignore_val = T;
现在部分专门化
C
p>
//未使用的主模板
模板< size_t N,typename = std :: make_index_sequence& C类;
// Partial specialization
template< size_t N,std :: size_t ... indices>
class C< N,std :: index_sequence< indices ...>>
{/ * ... * /};
部分特化中的构造函数的定义现在变得不重要
C(ignore_val< indices,B&> ... args):
member {args.getA()...}
{}
此外,您不必担心大量专业化。
Background : I've created the following class
C
, whose constructor should takeN
variables of typeB&
:class A; class B { A* getA(); }; template<size_t N> class C { public: template<typename... Args> inline C(Args&... args) : member{args.getA()...} {} private: std::array<A*, N> member; };
Problem : my problem is how to constraint the variadic
Args
to be all of typeB
?My partial solution : I wanted to define a predicate like :
template <typename T, size_t N, typename... Args> struct is_range_of : std::true_type // if Args is N copies of T std::false_type // otherwise {};
And redefine my constructor accordingly :
template <typename... Args, typename = typename std::enable_if<is_range_of_<B, N, Args...>::value>::type > inline C(Args&... args);
I've seen a possible solution on this post : http://stackoverflow.com/a/11414631, which defines a generic
check_all
predicate :template <template<typename> class Trait, typename... Args> struct check_all : std::false_type {}; template <template<typename> class Trait> struct check_all<Trait> : std::true_type {}; template <template<typename> class Trait, typename T, typename... Args> struct check_all<Trait, T, Args...> : std::integral_constant<bool, Trait<T>::value && check_all<Trait, Args...>::value> {};
So, I could write something like :
template <typename T, size_t N, typename... Args> struct is_range_of : std::integral_constant<bool, sizeof...(Args) == N && check_all<Trait, Args...>::value > {};
Question 1 : I don't know how to define the
Trait
, because I need somehow to bindstd::is_same
withB
as first argument. Is there any means of using the genericcheck_all
in my case, or is the current grammar of C++ incompatible ?Question 2 : My constructor should also accept derived classes of
B
(through a reference toB
), is it a problem for template argument deduction ? I am afraid that if I use a predicate likestd::is_base_of
, I will get a different instantiation of the constructor for each set of parameters, which could increase compiled code size...Edit : For example, I have
B1
andB2
that inherits fromB
, I callC<2>(b1, b1)
andC<2>(b1, b2)
in my code, will it create two instances (ofC<2>::C<B1, B1>
andC<2>::C<B1, B2>
) ? I want only instances ofC<2>::C<B, B>
.解决方案Define
all_true
astemplate <bool...> struct bool_pack; template <bool... v> using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
And rewrite your constructor to
// Check convertibility to B&; also, use the fact that getA() is non-const template<typename... Args, typename = std::enable_if_t<all_true<std::is_convertible<Args&, B&>{}...>{}> C(Args&... args) : member{args.getA()...} {}
I am afraid that if I use a predicate like std::is_base_of, I will get a different instantiation of the constructor for each set of parameters, which could increase compiled code size...
enable_if_t<…>
will always yield the typevoid
(with only one template argument given), so this cannot beis_base_of
s fault. However, whenArgs
has different types, i.e. the types of the arguments are distinct, then subsequently different specializations will be instantiated. I would expect a compiler to optimize here though.
If you want the constructor to take precisely
N
arguments, you can use a somewhat easier method. Definetemplate <std::size_t, typename T> using ignore_val = T;
And now partially specialize
C
as// Unused primary template template <size_t N, typename=std::make_index_sequence<N>> class C; // Partial specialization template <size_t N, std::size_t... indices> class C<N, std::index_sequence<indices...>> { /* … */ };
The definition of the constructor inside the partial specialization now becomes trivial
C(ignore_val<indices, B&>... args) : member{args.getA()...} {}
Also, you do not have to worry about a ton of specializations anymore.
这篇关于检查所有可变参数模板参数的traits的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!