1

I know that it isn't possible to have class methods that are both pure virtual and static (see this discussion). So, I ask: is there a way to guarantee that a bunch of derived classes have static functions that do the same thing and that are guaranteed to be named in the same way?

Consider the following example:

#include <iostream>
#include <array>

// class base {
// public:
//  virtual static constexpr size_t nums() = 0
// }

template<size_t num>
class derived1 {//: public base {
public:
    static constexpr size_t nums() {return num;}
    derived1()  {}
};

template<size_t num>
class derived2 {// : public base {
public:
    static constexpr size_t nums() {return num;}
    derived2()  {}
};

int main() {

    std::cout << derived2<20>::nums() << "\n";
    return 0;
}

I commented out the base class so that it compiles, but I want an interface class that guarantees a bunch of derived classes all have nums() named in the same way. In this particular example nums is named the same way in both derived class, but if I write a third derived class a few years from now, and I forget this convention, I don't want to be able to compile anything, ideally.

Taylor
  • 1,797
  • 4
  • 26
  • 51
  • Declare one base normal non-template class, declare there all your static variables and functions. Then all your templates derive that class and you have statics. – arin-berd Apr 08 '21 at 22:01
  • @arin-berd why can’t the base class be templated? I can also jusy make public data members and assign to them the template parameter integers – Taylor Apr 08 '21 at 22:10
  • Yep. For your very example (size_t nums() {return num;}) a base template for all can work fine. Just keep in mind the method will not be static. – arin-berd Apr 08 '21 at 22:13
  • Re: “if I write a third derived class a few years from now, and I forget this convention” **and** you don’t read the documentation, yes, you’ll be in trouble. Document requirements. – Pete Becker Apr 08 '21 at 22:23
  • If you don't call a function, you don't need to define it. If you do call a function, and you don't define it, you get a compilation error. Thus in order to guarantee that your class has a function, just call it. Of course nothing in the world can guarantee you that two functions do the same thing, for any reasonable value of "the same". – n. m. could be an AI Apr 08 '21 at 23:07

1 Answers1

1

You could use CRTP as the base class, and then have a routine that depends on the derived class having implemented the expected static function.

Here's an example, and I have thunk_nums in the base class dependent on the derived class having nums, although they could have been named the same.

Note that if a function isn't used, it won't be generated, and so won't trigger an error. (Which may be desired behavior, or if not desired then steps would have to be taken to ensure it is generated.)

#include <iostream>

template <typename DERIVED>
class base {
public:
    static constexpr size_t thunk_nums() {
        return DERIVED::nums();
    }
};

template<size_t num>
class derived1 : public base<derived1<num>> {
public:
    static constexpr size_t nums() {return num;}
    derived1() {}
};

template<size_t num>
class derived2 : public base<derived2<num>> {
public:
    static constexpr size_t nums() {return num;}
    derived2() {}
};

int main() {
    std::cout << derived2<20>::thunk_nums() << "\n";
}
Eljay
  • 4,648
  • 3
  • 16
  • 27
  • CRTP is slick. When you say “isn’t used” does that mean not defined in the derived class? How do I get the compiler to throw an error when it isn’t defined? – Taylor Apr 08 '21 at 22:19
  • 1
    You could have the base constructor call a routine that exercises all of the static routines you want to be present in the derived classes, but have it return early on some condition so the routines are not actually invoked. But since they *might* be exercised then they'd have to be generated, which means the compiler would have to check that they exist. As a thought. – Eljay Apr 08 '21 at 22:22