简体   繁体   中英

Issue passing template type to function and using for local variable assignment c++

I have the following code:

template<typename T> void computeFractalDimensionData(RandomWalkMethods::LatticeType latticeType, gsl_rng* randNumGen) {

    int nD = 0;

    // if T is of type std::pair<int,int> then set no. of dimensions to 2
    if (typeid(T) == typeid(std::pair<int, int>)) {
        nD = 2;
    }

    // else if T is of type RWM::Triple<int,int,int> then set no. of dimensions to 3
    else if (typeid(T) == typeid(RandomWalkMethods::Triple<int, int, int>)) {
        nD = 3;
    }

    else {
        return;
    }

    // Create vector of T structs to store DLA structure results
    std::vector<T> aggResults;

    // Initialise particle spawning type and attractor type for DLA system
    RandomWalkMethods::ParticleSpawnType spawn = RandomWalkMethods::CONSTANT_RANDOM_BOUNDINGBOX_EDGE;
    RandomWalkMethods::AttractorDLAType attractor = RandomWalkMethods::POINT;

    // Under-estimate for fractal dimension of the DLA
    const double fractalDimUnderestimateRecip = 1 / 1.65;

    for (int i = 100; i <= 1000; i += 100) {

        // initialise spawnDiameter using: exp(log(n)/fDUR) = n^{1/fDUR}
        int spawnDiam = 2*static_cast<int>(std::pow(i, fractalDimUnderestimateRecip));

        // if system is 2-dimensional, compute DLA for 2D on given lattice
        if (nD == 2) {
            aggResults = RandomWalkMethods::diffusionLimitedAggregateRandomWalk2D(i, spawn, spawnDiam, latticeType, randNumGen, attractor);
        }

        // else if system is 3 dimensional, compute DLA for 3D on given lattice
        else if (nD == 3) {
            aggResults = RandomWalkMethods::diffusionLimitedAggregateRandomWalk3D(i, spawn, spawnDiam, latticeType, randNumGen, attractor);
        }

        // compute the minimum bounding radius which encloses all particles in the DLA structure
        double boundingRadius = std::sqrt(maxMagnitudeVectorOfMultiples< double, T >(aggResults));

    }


}

which I may call with a statement such as

computeFractalDimensionData< std::pair<int,int> >(lattice, randNumGen);

or

computeFractalDimensionData< RandomWalkMethods::Triple<int,int,int> >(lattice, randNumGen);    

where Triple is simply a struct I defined with 3 elements (essentially the same as std::pair but extended for 3 fields). Also, the functions diffusionLimitedAggregateRandomWalk2D and diffusionLimitedAggregateRandomWalk3D return types of std::vector<std::pair<int,int>> and std::vector<Triple<int,int,int>> respectively.

The issue is that when I call with either statement above I get the following errors (occurring at the assignment statements aggResults = ... ):

binary '=': no operator found which takes a right-hand operand of type 'std::vector<std::pair<int,int>,std::allocator<_Ty>>' (or there is no acceptable conversion)

and similarly for the case of Triple<int,int,int> . From what I understand, this implies that I'd need an overloaded assignment operator for these 2 structs - however I do not think that is the issue here as the following statement has been used correctly before in my program:

std::vector< std::pair<int,int> > aggResults = RandomWalkMethods::diffusionLimitedAggregateRandomWalk2D(nParticles, boundingBox, spawnDiam, latticeType, randNumGen, attractor, &diffLimAggFile);

So I know that I can assign the result of the DLA methods to variables of the correct type however the compiler complains if I try it through the use of passing a type to a template function as was shown above.

What is happening here and how would I go about solving this issue?

This comes from the fact that

aggResults = diffusionLimitedAggregateRandomWalk2D(i, spawn, spawnDiam, latticeType, randNumGen, attractor);

with aggResults being a std::vector<T> is compiled even if T is Triple<int, int, int> but diffusionLimitedAggregateRandomWalk2D returns a std::vector<std::pair<int, int>> .


Suggested solution : declare a templated function and specialize it for some T .

template<typename T>
void computeFractalDimensionData(RandomWalkMethods::LatticeType latticeType, gsl_rng* randNumGen);

template<>
void computeFractalDimensionData<std::pair<int, int>>(RandomWalkMethods::LatticeType latticeType, gsl_rng* randNumGen)
{
    // ...
}

template<>
void computeFractalDimensionData<Triple<int, int, int>>(RandomWalkMethods::LatticeType latticeType, gsl_rng* randNumGen)
{
    // ...
}

It makes more readable code and fails to compile the following line with a helping compilation error:

computeFractalDimensionData<void>(lattice, randNumGen);

YSC's solution is good. I want you just to notice that the following code in your function is a wrong use of templates:

    // if system is 2-dimensional, compute DLA for 2D on given lattice
    if (nD == 2) {
        aggResults = RandomWalkMethods::diffusionLimitedAggregateRandomWalk2D(i, spawn, spawnDiam, latticeType, randNumGen, attractor);
    }

    // else if system is 3 dimensional, compute DLA for 3D on given lattice
    else if (nD == 3) {
        aggResults = RandomWalkMethods::diffusionLimitedAggregateRandomWalk3D(i, spawn, spawnDiam, latticeType, randNumGen, attractor);
    }

Templates are for static polymorphism, and you are using dynamic code (these if (nd == ...) ) in a template function. Proper use of a static polymorphism could be introducing a template parameter dimension .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM