I'm learning C++. I have a Classroom class which should behave one way or another depending on the Configuration object that is being used. I could pass that Configuration object in the constructor when creating the Classroom object like this:
class Classroom {
private:
Configuration conf;
public:
Classroom(Configuration conf_){
conf = conf_;
}
/** more member functions that use conf **/
};
But I thought it would be cooler if I could use a template for it. The Configuration object would be passed as template argument when creating the Classroom object. This is what I came up with, but it doesn't work:
template<Configuration &conf>
class Classroom {
int doSomething(int n){
// member function that uses data in Configuration object
return n + conf.config_1;
}
};
struct Configuration {
public:
int config_1;
};
int main() {
Configuration conf;
conf.config_1 = 95;
Classroom<conf> myClassroom;// doesn't work
}
It says: error: the value of 'conf' is not usable in a constant expression.
What am I missing?
Explanation: A template parameter is a special kind of parameter that can be used to pass a type as argument.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
As seen in the above cited example, we can use more than one parameter for a template in C++.
You can do that with some limitations. The way you are trying to do it isn't valid. It's a matter of storage.
If you need more than one configuration around, you can define it as a static member of a class template or define a global array of Configuration
s:
struct Configuration {
int config_1;
};
template<int>
struct Accessor {
static Configuration configuration;
};
template<int N>
Configuration Accessor<N>::configuration;
template<Configuration &conf>
class Classroom {
int doSomething(int n){
return n + conf.config_1;
}
};
int main() {
Accessor<1>::configuration.config_1 = 95;
Classroom<Accessor<1>::configuration> myClassroom;
(void)myClassroom;
}
If you can stick with a single instance, you can even put it in the global scope and use it instead:
struct Configuration {
int config_1;
};
Configuration conf;
template<Configuration &conf>
struct Classroom {
int doSomething(int n){
return n + conf.config_1;
}
};
int main() {
conf.config_1 = 95;
Classroom<conf> myClassroom;
myClassroom.doSomething(42);
}
Other solutions are possible, but I'm sure you got the idea.
See the examples up and running on wandbox.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With