std :: enable_if类型检查

时间:2018-08-14 18:56:15

标签: c++ c++11 templates typechecking

我正在尝试编写一个函数,该函数可以将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. 如何在convertSamples()内转换std::enable_if内部的逻辑以执行检查?如果传入的类型相同,或者其中一个不是用于样本的类型,我想在编译时出错。我尝试遵循许多示例,但是语法对我来说仍然很陌生。

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

  3. 编译器在做什么以“填充”类型,这是什么时候发生的?即,我正在尝试使用OpenMP通过SIMD指令执行转换步骤,因此我希望在完成任何其他优化之前先选择模板类型。

2 个答案:

答案 0 :(得分:2)

答案:

  1. 非常简单:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-rsa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  2. 是,返回true。参见https://en.cppreference.com/w/cpp/types/is_integral

  3. 为特定类型创建函数(我们称“模板已实例化”),然后正常进行优化。

答案 1 :(得分:1)

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

第一个示例中,我使用函数重载来处理src和dest属于同一类型的情况。当它们存在时,该函数可以noop,而当它们不在时,您可以进行转换。如果不是,那么这将使其成为编译时。

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 converting\n";
        return;
    }

    std::cout << "converting\n";
}