ZincFur
ZincFur

Reputation: 59

Instantiating the templated function using variables

I have three pointers within a class, each of which are instantiation of a templated structure. I am trying to retrieve either of them using a get<>() method whose return type differs accordingly.

//Example program
#include <iostream>
#include <map>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
#include <boost/any.hpp>
class CBase {};
enum en {Aa = 1, Bb = 2, Cc = 3};
class A {
    public: 
    template<en dim>
    struct C : public CBase, boost::static_visitor<CBase *>{
        int x;
        C() {
          x = dim;
        }
        template <en t>
        CBase * operator()(C<t> *s) const {
          return s;
        }
    };

    C<Aa>* Aasd;
    C<Bb>* Bbsd;
    C<Cc>* Ccsd;
    std::map<en, boost::variant<C<Bb> *, C<Aa> *, C<Cc> * > > matrices;    

    A() {
        Aasd = new C<Aa>;
        Bbsd = new C<Bb>;
        Ccsd = new C<Cc>;
    matrices.insert(std::make_pair(Bb, Bbsd));
    matrices.insert(std::make_pair(Aa, Aasd));
    matrices.insert(std::make_pair(Cc, Ccsd));
   }

   template<en tt>
    C<tt>* get() {
     return static_cast<C<tt> *>(boost::apply_visitor(C<tt>(), matrices[tt]));   
    }

    ~A() {
     delete Aasd;
     delete Bbsd;
     delete Ccsd;
    }        
};

    template<>
    A::C<Aa>* A::get<Aa>() {
               return static_cast<C<Aa> *>(boost::apply_visitor(C<Aa>(), matrices[Aa]));
    }

    template<>
    A::C<Bb>* A::get<Bb>() {
               return static_cast<C<Bb> *>(boost::apply_visitor(C<Bb>(), matrices[Bb]));
    }

    template<>
    A::C<Cc>* A::get<Cc>() {
               return static_cast<C<Cc> *>(boost::apply_visitor(C<Cc>(), matrices[Cc]));
    }

int main()
{    
  A a;

  int i = 0;
  en samp = Aa;
  std::cout<<a.get<Aa>()->x<<std::endl; // This runs fine
  //std::cout<<a.get<samp>()->x<<std::endl; // This throws error: the value of 'samp' is not usable in a constant expression
  return 0;
}

I do understand that I need to specify a compile time constant to instantiate a template. However, in my case I would like to use a variable to retrieve either of the pointers. Any thoughts or suggestions on how to do that would be highly appreciated.

EDIT:

I am looking for alternate suggestions to retrieve the 'x' member of these 3 pointers Aasd, Bbsd, Ccsd as in the main function even if I have to completely remove the templates. It should be probably something like

en samp = Aa;
a.get(samp)->x = 6;
samp = Bb;
a.get(samp)->x = 5;

or

en samp = Aa;
a[samp]->x = 6;
samp = Bb;
a[samp]->x = 5;

Upvotes: 0

Views: 91

Answers (2)

PcAF
PcAF

Reputation: 2007

Make samp constant:

const en samp;

EDIT: There is why it works:

Because

Non-type Template argument has to be constant expression (known at compile time)

proof: N3337 14.3.2/1

A template-argument for a non-type, non-template template-parameter shall be one of:

...

  • for a non-type template-parameter of integral or enumeration type, a converted constant expression of the type of the template-parameter; or

...

And when is enumeration type variable constant expression?

N3337 5.19/2:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression

...

  • an lvalue-to-rvalue conversion (4.1) unless it is applied to
    • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or

...

and because in case of:

const en samp = Aa, samp refers to const object initialized with constant expression

Upvotes: 1

Aaron McDaid
Aaron McDaid

Reputation: 27153

Move x into CBase, and then return CBase * from get instead of C<T> *. That will at least fix the problem with the return value, allowing the calling code to access ->x easily.

Then you can have a simple method something like this (untested):

CBase* A::get(en x) {
    switch(x) {
        break; case Aa: return this->get<Aa>();
        break; case Bb: return this->get<Bb>();
        break; case Cc: return this->get<Cc>();
    }
}

Upvotes: 0

Related Questions