使用typeid分隔代码执行

时间:2017-05-27 18:42:12

标签: c++ templates types

这个问题源于需要调用遗留C例程(FFTW),它们在模板化的C ++类中具有不同的函数名称,具体取决于类型(单/双/四倍精度)。这个错误的代码示例给出了我可能想要做的一个简单示例:

#include <cstdio>
#include <cmath>
#include <typeinfo>
#include <cstdlib>

void fcnd(double *x) {
    *x = pow(*x, 2);
    printf("%f\n", *x);
}

void fcnf(float *x) {
    *x -= 1;
    printf("%f\n", *x);
}

template <typename T> class Class {

public:
    void fcn() {
        T *var;
        if (typeid(T) == typeid(float)) {
            var = (float *) malloc(sizeof(float));
        } else if (typeid(T) == typeid(double)) {
            var = (double *) malloc(sizeof(double));
        }

        *var = 1.0;

        if (typeid(T) == typeid(float)) {
            fcnf(var);
        } else if (typeid(T) == typeid(double)) {
            fcnd(var);
        }
        free(var);
    }
};

int main() {
    Class<double> x;
    Class<float> y;

    x.fcn();
    y.fcn();
}
海湾合作委员会抱怨:

test.cpp: In instantiation of 'void Class<T>::fcn() [with T = double]': test.cpp:42:11:   required from here test.cpp:22:17: error: cannot convert 'float*' to 'double*' in assignment
             var = (float *) malloc(sizeof(float));
                 ^ test.cpp:30:17: error: cannot convert 'double*' to 'float*' for argument '1' to 'void fcnf(float*)'
             fcnf(var);
                 ^ test.cpp: In instantiation of 'void Class<T>::fcn() [with T = float]': test.cpp:43:11:   required from here test.cpp:24:17: error: cannot convert 'double*' to 'float*' in assignment
             var = (double *) malloc(sizeof(double));
                 ^ test.cpp:32:17: error: cannot convert 'float*' to 'double*' for argument '1' to 'void fcnd(double*)'
             fcnd(var);
                 ^

现在,我知道这里的错误是什么。我的问题是,为什么C ++不允许这样做?当然这是安全的,对吧?我认为专业化可能对此有所帮助,总是正确的方法吗?

2 个答案:

答案 0 :(得分:5)

基于模板参数调用函数可以在C ++ 17中完成:

extension UIView {
    func setNeedsLayoutForSubviews() {
        self.subviews.forEach({
            $0.setNeedsLayout()
            $0.setNeedsLayoutForSubviews()
        })
    }
}

func refreshIpad() {
    DispatchQueue.main.async {
        self.view.setNeedsLayout()
        self.view.setNeedsLayoutForSubviews()
    }
}

如果您没有可用的C ++ 17,您可以使用基于template <typename T> class Class { public: void fcn() { // one line can do it T* var{ reinterpret_cast<T*>(std::malloc(sizeof(*var))) }; *var = 1.0; // C++17's if constexpr does exactly what you need if constexpr (std::is_same_v<T, float>) { fcnf(var); } else if constexpr (std::is_same_v<T, double>) { fcnd(var); } free(var); } }; 的调度程序,其中包含模板特化或只是一个简单的重载函数。

T

注意:我希望在您的真实代码中检查调用auto set(float* f) noexcept { return fcnf(f); } auto set(double* d) noexcept { return fcnd(d); } template <typename T> class Class { public: void fcn() { T* var{ reinterpret_cast<T*>(std::malloc(sizeof(*var))) }; *var = 1.0; set(var); // there's a reason we have function overloading in C++ free(var); } }; 的结果。

答案 1 :(得分:0)

为什么不定义重载函数,而不是创建模板类:

void fcn(double& x) {
    fcnd(&x);
}

void fcn(float& x) {
    fcnf(&x);
}

此外,如果函数的名称仅因某些标准后缀集(表示类型)而不同,您甚至可以使用宏来轻松定义所有可用函数的重载:

#include <cstdio>
#include <cmath>
#include <iostream>

using namespace std;

/*
    Some C functions, actually defined elsewhere...
*/

void fcnd(double *x) {
    *x = pow(*x, 2);
}

void fcnf(float *x) {
    *x -= 1;
}

/*
    Some macros to simplify things
*/

#define define_overloaded_function_for(name, type, suffix)\
void name(type& x) { name##suffix(&x); }

#define define_overloaded_functions_for(name)\
define_overloaded_function_for(name, float, f)\
define_overloaded_function_for(name, double, d)\
/* define_overloaded_function_for(name, long double, ld) */

/*
    Define some functions
*/
define_overloaded_functions_for(fcn);
/* ...etc... */

int main(void) {
    float a = 705;
    double b = 2465;
    cout << "~ a ~" << endl;
    cout << a << endl;
    fcn(a);
    cout << a << endl;
    cout << "~ b ~" << endl;
    cout << b << endl;
    fcn(b);
    cout << b << endl;
}