10

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?

zku11126
  • 103
  • 1
  • 4
  • template instantiation is done by the compiler. So what you pass as a template argument should be known at the compile time – Artemy Vysotsky Aug 26 '17 at 20:01
  • Missing keyword `typename or class`. – Raindrop7 Aug 26 '17 at 20:04
  • 5
    _"But I thought it would be cooler if I could use a template for it."_ Don't do things because you think they're _cool_. Have a reasonable use case in 1st place. – user0042 Aug 26 '17 at 20:04
  • [Move your object up a level](https://wandbox.org/permlink/2LTZEOWI2Ns1jMwl). – skypjack Aug 27 '17 at 04:04
  • Or [make a static object in a class template out of your configuration](https://wandbox.org/permlink/jg0jDSEqQPW0jqf8) if you need to have more than one configuration around. – skypjack Aug 27 '17 at 04:26
  • 1
    @user0042 I agree. But as long as you are aware of what you're doing and the purpose is to learn and explore (and not writing production code), I think it's fine to do things **the cool way** :) – Vijay Chavda Oct 29 '19 at 09:55

2 Answers2

6

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 Configurations:

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.

skypjack
  • 49,335
  • 19
  • 95
  • 187
0

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);
}
user0042
  • 7,917
  • 3
  • 24
  • 39
  • You can even have [more than one configuration](https://wandbox.org/permlink/jg0jDSEqQPW0jqf8) and still do that. – skypjack Aug 27 '17 at 04:27