Reputation: 103
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?
Upvotes: 10
Views: 7005
Reputation: 50550
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.
Upvotes: 6
Reputation: 8018
Template parameters are meant to be types or at least a restricted set of literals or enum values which are known at compile time.
So you cannot do that.
What you can do though is something like
template<typename ConfType>
class Classroom {
const ConfType& conf_;
public:
// Provide a constructor that takes a reference to the Configuration type
Classroom(const ConfType& conf) : conf_(conf) {}
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<Configuration> myClassroom(conf);
}
Upvotes: 0