5

I have a

template <int N> class Base

and

class Derived : public Base<1>

... is there a way to access the int N from inside the definition of a Derived::myMethod() (instead of getting the compiler error "use of undeclared identifier 'N'")?

More precisely, I would like to do

void Derived::myMethod() {
   for (int n=0; n<N; n++) { ...
PhilippJS
  • 51
  • 2
  • 2
    Why don't you just write 1 instead of N? What are you trying to do? – Luchian Grigore Aug 08 '12 at 20:55
  • Seems an odd question, because you know that N is 1. – jahhaj Aug 08 '12 at 20:55
  • 2
    Right, I know that N==1. But I will have lots of occurrences of "1" in `Derived::myMethod()`, and I would like to think there is a smarter way to change the value of N during development than having to manually update all "1" to some new value. – PhilippJS Aug 08 '12 at 21:03

3 Answers3

5

The template argument has the scope of the template, but you can define a nested constant in the template that can be used by derived classes:

template <int N> class Base {
public: // or protected:
   static const int theN = N;
};
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 2
    +1 for creativity, but if he needs to do this, I think it's more likely a design problem... – Luchian Grigore Aug 08 '12 at 20:59
  • My guess is that it *is* a design problem. I am guessing that he has created a templated container and is using inheritance from it (instead of composition) while at the same time trying to access the the container through some protected rather than public interface. But my crystal ball might be off... – David Rodríguez - dribeas Aug 08 '12 at 21:04
  • I hate it when my crystal ball is off... :( – Luchian Grigore Aug 08 '12 at 21:06
  • @David: +1 thanks, that would work. It's not what I had expected, though - might this not in general allocate memory for that additional const at least once (even if it's a static variable, unless it gets optimized away)? Also, on a more stylistic note, now I have duplicated access to this value (both through N and theN), which is not very minimalist. – PhilippJS Aug 08 '12 at 21:06
  • @David+Luchian: Of course it might be a design issue... but what I am trying to achieve is: I have a template class that gets specialized on a number of capture devices, and now I want to derive a class that implements special operations for the N=1 case. However, this derived class is *not* just a specialization of the template for N=1. – PhilippJS Aug 08 '12 at 21:10
  • @PhilippJS: If you don't provide a *definition* for the static constant, then no space will be wasted, that also means that if you *odr-use* it you will get a linker error as the variable is not defined. You can alternatively use an `enum` for this. Finally, if this is an specialization only for `1`, why do you need it? – David Rodríguez - dribeas Aug 08 '12 at 21:19
  • @David: thanks for the ref to "odr-use"... learned sth new. `enum` would also be a solution - but this suffers from the same style issue as the `static const` approach: It clutters the scope of `Base` with additional symbols. Finally, "why"? Because Base<1> contains a couple of well-defined (aka "useful") methods that I don't want to reimplement anywhere, but one of them - `myMethod()` - needs a reimplement very (application-)specific to `Derived`, and which thus should not be done in a specialization `Base<1>::myMethod()`. – PhilippJS Aug 08 '12 at 21:31
1

One other option is you could template the derived class:

template <int N>
class Derived : public Base<N>
{
    void myMethod()
    {
        for (int i = 0; i < N; ++i)
        //
    }
};
Jesse Good
  • 50,901
  • 14
  • 124
  • 166
  • 1
    Yes, but there will be no uses of Derived for N!=1 ... ever... so it will be an undue burden on the users of Derived (and also exposes implementation details) to specify <1> every time they instantiate it. – PhilippJS Aug 08 '12 at 21:26
  • This is how I would do it (If I ultimately needed for some reason to use the template parameter this way. It seems odd to me that the N is templated at all. Do you really need to have an instantiation for each and every value of N (Seems like this could lead to serious code bloat). @PhilippJS Why is 1 required for a template at all, given your comment to Jesse answer. Could this not be a member intialized at construction? See my answer below... – clanmjc Aug 08 '12 at 21:28
  • @clanmjc: As I explained in a comment above, Base represents a bunch of N capture devices. For `Derived`, I have only one - but very specific - capture device that needs special treatment in `myMethod()`. I have some copy-paste of code from `Base::myMethod()` to `Derived::myMethod()`, but I would like to keep structure changes minimal to avoid errors. Re "member initialized at construction (of `Derived`, I guess)" - again, I would have to hardcode "Derived::myN(1)" in the element initializer list, no? – PhilippJS Aug 08 '12 at 21:37
  • See my answer below about hardcoding. Also, is N literally an int, or is N some object. However you dice it, including in your example, somewhere there will be 1 hardcoded. However, this doesn't mean that the Dervied class needs to know anything about this detail. – clanmjc Aug 08 '12 at 21:40
0

This is what I meant from my comment above:

class Base{
  public:
     Base(int value = 1) : value_(value){}  //don't need to use default param but can
  private:
     int value_
}

class Derived : public Base
{}

Why templatize N? Do you need to specialize the entire class? An alternative would be "virtualizing" non member functions that are called from the template based on the criteria you set as "specialization".

Edit: Partial specialization of a method in a templated class

Community
  • 1
  • 1
clanmjc
  • 299
  • 1
  • 9