Search code examples
c++pointerspolymorphismtype-safety

Alternative for void pointers in modern C++


I want to retreive data from a source, made available through one function, by a set of different functions. I come from c, so I have this example:

#include <iostream>

using namespace std;

void getInt(void *v, const double &src) {*static_cast<int*>(v) = src; }
void getDouble(void *v, const double &src) {*static_cast<double*>(v) = src; }

struct twoInt{int a; int b;};
void getTwoInt(void *v, const double &src)
{
    static_cast<twoInt*>(v)->a = src;
    static_cast<twoInt*>(v)->b = static_cast<int>(src*10) % 10;
}

template <typename T>
void getData(T f, void* val)
{
    double dataSource = 2.1;
    f(val, dataSource);
}


int main()
{
    int valI;
    double valD;
    twoInt valTwoInt;

    getData(getInt, static_cast<void*>(&valI));
    cout << "Int: " << valI << endl;

    getData(getDouble, static_cast<void*>(&valD));
    cout << "Double: " << valD << endl;

    getData(getTwoInt, static_cast<void*>(&valTwoInt));
    cout << "Int1: " << valTwoInt.a << ", Int2: " << valTwoInt.b <<endl;
}

But I would like to do it in a modern C++ way, and without the void pointers, to have more type safety.


Solution

  • You don't need type erasure here, so correct type and template do the job:

    void getInt(int& out, double src) { out = src; }
    void getDouble(double& out, double src) { out = src; }
    
    struct twoInt{int a; int b;};
    void getTwoInt(twoInt& v, double src)
    {
        v.a = src;
        v.b = static_cast<int>(src * 10) % 10;
    }
    
    template <typename F, typename T>
    void getData(F f, T& val)
    {
        double dataSource = 2.1;
        f(val, dataSource);
    }
    
    int main()
    {
        int valI;
        getData(getInt, valI);
        std::cout << "Int: " << valI << std::endl;
    
        double valD;
        getData(getDouble, valD);
        std::cout << "Double: " << valD << std::endl;
    
        twoInt valTwoInt;
        getData(getTwoInt, valTwoInt);
        std::cout << "Int1: " << valTwoInt.a << ", Int2: " << valTwoInt.b <<std::endl;
    }
    

    Demo