标准::enable_if类型检查

std::enable_if type checking

本文关键字:类型 检查 if enable 标准      更新时间:2023-10-16

我正在尝试编写一个可以将T2类型的缓冲区转换为T1类型的缓冲区的函数。围绕此函数的大部分代码都非常类似于 C,因此我必须接受指向缓冲区的原始指针。缓冲区包含数字样本。对于浮点缓冲区(floatdouble等(,最小可能值为 -1.0,最大值为 1.0。对于整数类型,示例跨越类型的范围。例如,int16_t样本从 -32,768 运行到 32,767。因此,除了类型转换之外,还有更多的事情要做,通常需要使用比例因子进行乘法才能使样本进入正确的范围。

过去,我遇到过为每种可能的样本类型编写专用转换的库。老实说,我来自嵌入式背景,我通常会做同样的事情(我正在尝试学习更现代的C++技术,而不仅仅是将语言视为"带有类的 C"(,但是我可以看到这种方法会导致大量代码被复制粘贴并且仅略微编辑。

到目前为止,我认为我的模板化方法似乎有效,但我想在编译时用std::enable_if强制执行我的类型检查(如果有人尝试转换不用于示例的类型,我希望编译器出错(。到目前为止,我拥有的代码在下面复制。

template <class T>
struct is_sample_type : std::integral_constant <
bool,
(std::is_floating_point<T>::value || std::is_integral<T>::value)> {};
template <typename T1, typename T2>
void convertSamples(T1* const dst, const T2* const src,
const size_t num_samples, const double scalar) {
if ((!is_sample_type<T1>::value) || (!is_sample_type<T2>::value))
throw std::invalid_argument("Invalid sample type passed in.");
if (std::is_same<T1, T2>::value) return;  // nothing to convert
// Do conversion...
}

我有几个问题:

  1. 如何使用std::enable_if转换convertSamples()中的逻辑以在编译时执行检查?如果传入的类型相同,或者任何一个不是用于示例的类型,我想在编译时出错。我试图遵循许多示例,但语法对我来说仍然很陌生。

  2. 对于stdint.h中定义的整数类型,std::is_integral是否返回 true?我认为这是真的,因为这些只是别名。

  3. 编译器在后台做什么来"填充"类型,何时发生?也就是说,我正在尝试使用 OpenMP 通过 SIMD 指令执行转换步骤,因此我希望在进行任何其他优化之前选择模板类型。

答案:

  1. 非常简单:

    static_assert(is_sample_type<T1>::value && is_sample_type<T2>::value), "Please use sample types");
    
  2. 是,返回 true。见 https://en.cppreference.com/w/cpp/types/is_integral

  3. 为特定类型创建函数(我们说"模板已实例化"(,然后正常优化。

这是一种在编译时确定输入是否符合要求以及它们是否需要转换的方法(假设相同类型意味着没有转换(。 我更改了您的元函数 IsSample 以使用布尔模板变量,因为我认为它更干净。

第一个示例,我使用函数重载来处理 src 和 dest 是同一类型的情况。 当它们是时,该功能可以运行,当它们不是时,您可以转换。 这使它成为编译时 if 而不是运行时 if。

template <typename T>
constexpr bool is_sample = std::is_floating_point<T>::value || std::is_integral<T>::value;
template <typename T1, typename T2,  typename=std::enable_if_t<is_sample<T1> && is_sample<T2>>>
void convertSamples(T1* dst, const T2* src, size_t num_samples, double scalar) {
std::cout << "converting...n";
}
template <typename T,  typename=std::enable_if_t<is_sample<T>>>
void convertSamples(T* dst, const T* src, size_t num_samples, double scalar) {
std::cout << "NOT converting (noop)n";
}

您还可以方便地使用 c++17 "if constexpr" 来合并这些内容,该函数与上述大致相同,但在单个函数中。

template <typename T1, typename T2, typename = std::enable_if_t<is_sample<T1> && is_sample<T2>>>
void convertSamples(T1* dst, const T2* src, size_t num_samples, double scalar) {
if constexpr (std::is_same_v<T1, T2>) {
std::cout << "not convertingn";
return;
}
std::cout << "convertingn";
}