#include <cstdlib>
#include <iostream>



/**
Test Class for learning template-metaprogramming
*/

using namespace std;

template<int N> //General case for a number
class ShowValues {
public:
    static inline void show()
    {   
        cout << "Start: " << N << endl;
        ShowValues< (N > 1) ? (N - 1): 1>::show();
        cout << "Finish: " << N << endl;
    }
};

template<>
class ShowValues<1> { //specialized case for when N = 1
public:
    static inline void show()
    {
        cout << "Reached 1" << endl;    
    }
};

struct MyStruct
{
       public:
              
            int x, y;
       
            MyStruct(int first=0, int second=0): x(first), y(second){};
            int getX(){return x;};
            int getY(){return y;};
};


typedef class RestrictedTemplateClass
{
      public:
      
      template<MyStruct &B> //template that has a restricted parameter - must be a MyStruct reference or greater
      static void displayParameters()
      {
           cout << B.getX() << ", " << B.getY() << endl;
      };
}RTC;

int main(int argc, char *argv[])
{
    
    const MyStruct *const mStruct = new MyStruct (1, 2);
    
  //  RTC::displayParameters<mStruct*>(); //apparantly this doesnt work?
    
  //  ShowValues<10>::show();
    cin.get();
    return 0;
};

Why is it that I cannot call th method in RTC::displayParameters() with the template-argument mStruct* when it is clearly a constant reference?

The errors I receive when I uncomment the code are--

... In function `int main(int, char**)': 
60 ... `mStruct' cannot appear in a constant-expression 
60 ... template argument 1 is invalid 
60 ... no matching function for call to `RestrictedTemplateClass::displayParameters()' 
... [Build Error]  [testingTemplateRecursion.o] Error 1

Recommended Answers

All 5 Replies

>Why is it that I cannot call th method in RTC::displayParameters() with
>the template-argument mStruct* when it is clearly a constant reference?
Because it clearly isn't. Let's start with the fact that <mStruct*> is a syntax error. The closest interpretation would be to call the instantiation of displayParameters using a pointer to mStruct. But mStruct isn't a type, and displayParameters doesn't even have a specialization that takes a type. So let's move that asterisk to a better location and work from your perceived problem:

const MyStruct * const mStruct = new MyStruct ( 1, 2 );

RTC::displayParameters<*mStruct>();

*mStruct is constant, but not the compile-time constant that templates require because you're using dynamic memory. But even if you remove that and make it a straight const object, it still won't work:

const MyStruct mStruct ( 1, 2 );

RTC::displayParameters<mStruct>();

Why? Because the local variable doesn't represent a compile-time constant either. To get a suitable constant object, the variable has to be non-local and have external linkage:

extern const MyStruct mStruct ( 1, 2 );

int main(int argc, char *argv[])
{
  RTC::displayParameters<mStruct>();
}

Furthermore, because the object has to be pretty darned constant, you need to specialize the template for that as well if you intend it to work:

template<const MyStruct &B>
static void displayParameters()
{
  cout << B.getX() << ", " << B.getY() << endl;
}

And of course, because the object is const, the member functions you use must be const as well:

struct MyStruct {
public:
  int x, y;

  MyStruct(int first=0, int second=0): x(first), y(second){};

  int getX() const {return x;}
  int getY() const {return y;}
};

The long and the short of things is that you'll have an easier time just sprinkling const everywhere that it's valid before trying something like this. Actually, you'll have an easier time in general if you make as much of the world const as you can.

template<>
class ShowValues<1> { //specialized case for when N = 1
public:
    static inline void show()
    {
        cout << "Reached 1" << endl;    
    }
};

struct MyStruct
{
       public:
              
            int x, y;
       
            MyStruct(int first=0, int second=0): x(first), y(second){};
            const int getX()const{return x;};
            const int getY()const{return y;};
};


typedef class RestrictedTemplateClass
{
      public:
      
      template<const MyStruct &B> //template that has a restricted parameter - must be a MyStruct reference or greater
      const static void displayParameters()
      {
           cout << B.getX() << ", " << B.getY() << endl;
      };
}RTC;

int main(int argc, char *argv[])
{
    
    extern const MyStruct mStruct ( 1, 2 );
    
    RTC::displayParameters<mStruct>();
    
  //  ShowValues<10>::show();
    cin.get();
    return 0;
};

I tried to be as constant as possible... I got the following errors--

... In function `int main(int, char**)': 
58 ...`mStruct' has both `extern' and initializer
60 ... `mStruct' cannot appear in a constant-expression
60 ... template argument 1 is invalid
60 ... no matching function for call to `RestrictedTemplateClass::displayParameters()' 
 ... [Build Error]  [testingTemplateRecursion.o] Error 1

This is my first time dealing with extern. I've seen it a few times but I never practiced using it.

>I tried to be as constant as possible... I got the following errors--
When I move around code, I do it for a reason. In this case, I moved the definition of mStruct outside of main because extern variables can't be initialized there. Oddly enough, your error says just that. :icon_rolleyes:

Here's some complete code for you to work with:

#include <iostream>

using namespace std;

struct MyStruct {
public:
  int x, y;

  MyStruct ( int first=0, int second = 0 )
    : x ( first ), y ( second )
  {};

  const int getX() const { return x; }
  const int getY() const { return y; }
};


class RestrictedTemplateClass {
public:
  template<const MyStruct &B>
  const static void displayParameters()
  {
    cout<< B.getX() << ", " << B.getY() <<'\n';
  }
};

extern const MyStruct mStruct ( 1, 2 );

int main()
{
  typedef RestrictedTemplateClass RTC;

  RTC::displayParameters<mStruct>();
}

>I tried to be as constant as possible... I got the following errors--
When I move around code, I do it for a reason. In this case, I moved the definition of mStruct outside of main because extern variables can't be initialized there. Oddly enough, your error says just that. :icon_rolleyes:

Thanks Narue =)

I admit I didn't pay enough attention when I saw the reply. My own fault.

a nontype template parameter can be a pointer or a reference to an object with external linkage.
the object itself need not be a constant. eg.

struct A
{
  explicit A( int ii=7 ) : i(ii) {}
  void modifier() { ++i ; }
  int i ;
};

struct rtc
{
  template< A* pointer >
  static inline void do_modify_via_ptr() { pointer->modifier() ; }

  template< A& reference >
  static inline void do_modify_via_ref() { reference.modifier() ; }
};

A a ; // object with external linkage

int main()
{
  rtc::do_modify_via_ptr< &a >() ;
  rtc::do_modify_via_ref< a >() ;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.