我已经定义了一个作为整数的类型。我想为我的类型定义 std::common_type 的专业化。但是,这种特化应该能够结合任意数量的其他参数(其他有界整数或内置整数类型)给出有界整数类型的 common_type。我希望以下代码全部有效:
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, long, short, long long, short, bounded_integer<1, 10>, int, short, short, short, ..., short, bounded_integer<1, 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(built-in integer value) 函数将它们的整数转换为 bounded_integer (因此对于内置类型与 bounded_integer 的组合,没有专门的 common_type )
- 从不将 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, intmax_t maximum, typename... Ts, 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, maximum>, Ts...> {
};
template<typename T1, typename T2, intmax_t minimum, intmax_t maximum, typename... Ts, typename = typename std::enable_if<all_are_integral<T1, T2>::value>::type, typename = typename std::enable_if<all_bounded_integer_or_builtin<Ts...>::value>::type>
class common_type<T1, T2, bounded_integer<minimum, maximum>, 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
and unsigned
,它遵循标准的积分提升规则,给出unsigned
。然后它返回common_type
withunsigned
和 my的结果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)
的和是。common_type
_ 例如:http: //ideone.com/9IxKIW。Standardese 可以在 § 20.9.7.6/3 中找到,其中两个值的int
unsigned
unsigned
common_type
typedef decltype(true ? declval<T>() : declval<U>()) type;
在第 5.16/6 节中,它说
第二和第三个操作数有算术或枚举类型;执行通常的算术转换以将它们转换为通用类型,并且结果属于该类型。
通常的算术转换在第 5/9 节中定义为
否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。