Question

I would like to create a map of integers to objects of a templated class. The template parameter is an integer and the value of the template parameter is not known at compile time.

I've seen this question: C++: Passing a variable as a template argument and it helps, but I'm still a little stuck. I'm trying to avoid a switch/case statement; I don't want to write many cases.

My example below doesn't compile, but it gets at the meat of what I'm trying to do. Can someone help me finish this out?

#include <iostream>
#include <map>

class File{
    public:
        File(int MF): mf(MF) {  }
        int mf;
};

template <int MF>
class tFile: public File{
    public:
        tFile(): File(MF){   }
        void print() { std::cout << "MF=" << MF << std::endl;}
};

File* createMF0(){
    return new tFile<0>;
}
File* createMF1(){
    return new tFile<1>;
}
File* createMF2(){
    return new tFile<2>;
}
File* createMF3(){
    return new tFile<3>;
}

int main(){

    std::cout << "\nI'm learning about templates." << std::endl;

    File myFile(3);
    std::cout << "\nmyFile  has MF=" << myFile.mf << std::endl;

    tFile<4> myTFile;
    std::cout << "myTFile has ";
    myTFile.print();

    // Now for the real stuff
    std::map<int, std::function<File*>> createMF;
    std::map<int, File*> templateFiles;

    createMF[0] = createMF0;
    createMF[1] = createMF1;
    createMF[2] = createMF2;
    createMF[3] = createMF3;

    // Here I'm trying to avoid a switch statement
    std::cout << std::endl;
    for (int i=0; i <= 3; i++){
        std::cout << "i = " << i << std::endl;
        templateFiles[i] = createMF[i]();
    }

    return 0;
}
Was it helpful?

Solution

Change the line

std::map<int, std::function<File*>> createMF;

to

std::map<int, std::function<File*()>> createMF;

The type of the template parameter to instantiate the std::functional is not a File* but a function that has no arguments and returns a File*.

Update

You can simplify your code a little bit using another template. Instead of

File* createMF0(){
    return new tFile<0>;
}
File* createMF1(){
    return new tFile<1>;
}
File* createMF2(){
    return new tFile<2>;
}
File* createMF3(){
    return new tFile<3>;
}

You can have just one function:

template <int N>
File* createMF(){
    return new tFile<N>;
}

If you do that, the core of main function needs to be changed to:

// Now for the real stuff
std::map<int, std::function<File*()>> createFunctions;
std::map<int, File*> templateFiles;

createFunctions[0] = createMF<0>;
createFunctions[1] = createMF<1>;
createFunctions[2] = createMF<2>;
createFunctions[3] = createMF<3>;

// Here I'm trying to avoid a switch statement
std::cout << std::endl;
for (int i=0; i <= 3; i++){
    std::cout << "i = " << i << std::endl;
    templateFiles[i] = createFunctions[i]();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top