c – 出现在可变参数模板参数包的任何位置的类型的类模板的部分特化

前端之家收集整理的这篇文章主要介绍了c – 出现在可变参数模板参数包的任何位置的类型的类模板的部分特化前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经定义了一个充当整数的类型.我想为我的类型定义std :: common_type的特化.但是,这种专门化应该能够将bounded_integer(我的类)的common_type与任何其他bounded_integer或内置整数类型的其他参数组合在一起.我希望以下代码都有效:
std::common_type<bounded_integer<1,10>>::type
std::common_type<bounded_integer<1,10>,int>::type
std::common_type<int,long,bounded_integer<1,10>>::type
std::common_type<int,int,short,long long,...,10>>::type

解决这个问题的第一个尝试是使用enable_if.但是,我意识到这不允许我区分common_type的库定义,正如我所拥有的那样

#include <type_traits>

class C {};

template<typename T,typename... Ts>
class contains_c {
public:
        static constexpr bool value = contains_c<T>::value or contains_c<Ts...>::value;
};
template<typename T>
class contains_c<T> {
public:
        static constexpr bool value = std::is_same<T,C>::value;
};

namespace std {

template<typename... Args,typename std::enable_if<contains_c<Args...>::value>::type>
class common_type<Args...> {
public:
        using type = C;
};

}       // namespace std

int main() {
}

“部分专业化”实际上只是“任何论据”,而不是我们所拥有的专业.

因此,似乎唯一的解决方案是要求我的用户执行以下操作之一:

>始终将bounded_integer作为common_type的第一个参数
>总是使用我的make_bounded(内置整数值)函数将它们的整数转换为bounded_integer(因此没有内置类型的common_type的特殊化与bounded_integer的组合)
>永远不要将bounded_integer放在大于N的位置,其中N是我确定的某个数字,类似于Visual Studio的旧的可变参数模板解决方法

3看起来像这样:

// all_bounded_integer_or_integral and all_are_integral defined elsewhere with obvIoUs definitions
template<intmax_t minimum,intmax_t maximum,typename... Ts,typename = type std::enable_if<all_bounded_integer_or_integral<Ts...>::value>::type>
class common_type<bounded_integer<minimum,maximum>,Ts...> {
};
template<typename T1,intmax_t minimum,typename = typename std::enable_if<all_are_integral<T1>::value>::type,typename = typename std::enable_if<all_bounded_integer_or_builtin<Ts...>::value>::type>
class common_type<T1,bounded_integer<minimum,typename T2,typename = typename std::enable_if<all_are_integral<T1,T2>::value>::type,T2,Ts...> {
};
// etc.

对于我无法更改原始定义的类,是否有更好的方法来实现此目的(当所有类型满足一个条件并且任何类型满足另一个条件时,模板专门化)?

编辑:

根据答案,我的问题不够明确.

首先,预期的行为:

如果有人调用std :: common_type,其中所有类型都是bounded_integer或内置数值类型的实例,我希望结果是bounded_integer,它具有所有可能的最小值和最大值的最小值.可能的最大值.

问题:

当有人在任意数量的bounded_integer上调用std :: common_type时,我有一个有效的解决方案.但是,如果我只专门化两个参数版本,那么我遇到了以下问题:

std :: common_type< int,unsigned,bounded_integer< 0,std :: numeric_limits< unsigned> :: max()1>

应该给我

bounded_integer< std :: numeric_limits< int> :: min(),std :: numeric_limits< unsigned> :: max()1>

但事实并非如此.它首先将common_type应用于int和unsigned,它遵循标准的整数提升规则,给出无符号.然后它返回common_type的结果,带有unsigned和我的bounded_integer,给出

bounded_integer< 0,std :: numeric_limits< unsigned> :: max()1>

因此,通过将unsigned添加到参数包的中间,即使它对结果类型完全没有影响(其范围完全包含在所有其他类型的范围内),它仍会影响结果.我能想到的唯一方法就是将std :: common_type专门用于任意数量的内置整数,后跟bounded_integer,后跟任意数量的内置整数或bounded_integer.

我的问题是:我怎么能这样做而不必通过手动写出任意数量的参数,然后是bounded_integer后跟参数包来近似它,或者这是不可能的?

编辑2:

common_type将给出错误值的原因可以通过遵循标准的这种推理来解释(引自N3337)

int和unsigned的common_type是无符号的.例如:http://ideone.com/9IxKIW. Standardese可以在§20.9.7.6/3中找到,其中两个值的common_type是

typedef decltype(true?declval< T>():declval< U>())type;

在第5.16 / 6节中,它说

The second and third operands have arithmetic or enumeration type; the
usual arithmetic conversions are performed to bring them to a common
type,and the result is of that type.

通常的算术转换在§5/ 9中定义为

Otherwise,if the operand that has unsigned integer type has rank
greater than or equal to the rank of the type of the other operand,
the operand with signed integer type shall be converted to the type of
the operand with unsigned integer type.

解决方法

std :: common_type将自己的双参数特化推断为n参数情形.您只需要专门化两个参数的情况.
template< typename other,int low,int high >
struct common_type< other,::my::ranged_integer< low,high > > {
    using type = other;
};

template< typename other,int high >
struct common_type< ::my::ranged_integer< low,high >,other > {
    using type = other;
};

template< int low,high > > {
    using type = ::my::ranged_integer< low,high >;
};

这留下了未定义的不同范围整数之间的common_type.我想你可以用min和max来做.

如果您的类支持继承,您还可以创建一个is_ranged_integer特征.

不要忘记将库放在命名空间中.

猜你在找的C&C++相关文章