Pregunta

I have a bunch of classes (which I never instantiate) that implement the same static inlined method in different ways. I am trying to understand if these classes can have a common parent. The purpose is not having virtual calls, but just to force a structure for anybody who wanted to write new classes implementing the method again in a different way. Can I do that? I am starting to think that is not a kind of feature C++ provides.

class XXX {
public:
    ///Should force any derived class to implement
    ///bool compute(const unsigned char i1, const unsigned char i2);
};

class GreaterThan : public XXX {
public:
    static inline bool compute(const unsigned char i1, const unsigned char i2) {
        return i1 > i2;
    }
};

class NotGreaterThan : public XXX {
public:
    static inline bool compute(const unsigned char i1, const unsigned char i2) {
        return i1 <= i2;
    }
};

class NotLessThan : public XXX { ///This should not compile
public:
    static inline bool compute2(const unsigned char i1, const unsigned char i2) {
        return i1 >= i2;
    }
};

[...]

Defining a pure virtual method compute in the base class doesn't allow me to define a static method in the derived class. Having the method not static would force me to instantiate the class when I use it as a functor, and would basically prevent inlining.

Note: A similar question was asked here.

Edit: Possibly, also this shouldn't compile:

class LessThan : public XXX { ///Also this should not compile
public:
    static inline bool compute(const float i1, const float i2) {
        return i1 < i2;
    }
};
¿Fue útil?

Solución 2

This should almost do what you want:

#include <iostream>

template <typename Algorithm>
class UnsignedCharFunction {
    public:
    typedef Algorithm algorithm_type;
    static bool compute(const unsigned char i1, const unsigned char i2) {
        return call(algorithm_type::do_compute, i1, i2);
    }

    private:
    static bool call(
        bool (*f)(const unsigned char, const unsigned char),
        const unsigned char i1, const unsigned char i2) {
        return f(i1, i2);
    }
};

class GreaterThan : public UnsignedCharFunction<GreaterThan> {
    friend class UnsignedCharFunction<GreaterThan>;

    private:
    static bool do_compute(const unsigned char i1, const unsigned char i2) {
        return i1 > i2;
    }
};


class Invalid : public UnsignedCharFunction<Invalid> {
    friend class UnsignedCharFunction<Invalid>;

    private:
    #define N 2
    #if N == 1
    // Fails
    static bool no_do_compute(const unsigned char i1, const unsigned char i2) {
        return i1 >= i2;
    }
    #elif N == 2
    // Fails
    static bool do_compute(char i1, char i2) {
        return i1 >= i2;
    }
    #endif
};


int main() {
    std::cout << "A > B:" << GreaterThan::compute('A', 'B') << '\n'
              << "B > A:" << GreaterThan::compute('B', 'A') << '\n';
    // If you comment next line, there will be no error.
    Invalid::compute('A', 'B');
}

It is almost, due instantiation of templates - an compiler error will only show up, when the function is used.

Regarding inline:

volatile bool value; 
int main() {
    value = GreaterThan::compute('A', 'B');
}

00000000004005a0 <main>:
  4005a0: movb   $0x0,0x200aa5(%rip)        # 60104c <value>
  4005a7: xor    %eax,%eax
  4005a9: retq   
  4005aa: nopw   0x0(%rax,%rax,1)

The code will completely elided in this simple little program.

Another inline:

volatile bool value;
volatile unsigned char a;
volatile unsigned char b;
int main() {
    value = GreaterThan::compute(a, b);
}

00000000004005a0 <main>:
  4005a0: movzbl 0x200aa5(%rip),%edx        # 60104c <b>
  4005a7: movzbl 0x200a9f(%rip),%eax        # 60104d <a>
  4005ae: cmp    %al,%dl
  4005b0: setb   %al
  4005b3: mov    %al,0x200a95(%rip)        # 60104e <value>
  4005b9: xor    %eax,%eax
  4005bb: retq   
  4005bc: nopl   0x0(%rax)

Both compiled with "g++ -std=c++11 -O3 -g"

Otros consejos

What you want is called static polymorphism.

You do not need inheritance at all. In your example, this should force users of XXX to implement bool compute(const unsigned char i1, const unsigned char i2); as static method :

template< typename C >
class XXX {
public:
    static void CallCompute(const unsigned char i1, const unsigned char i2)
    {
        const bool result = C::compute( i1, i2 );
        // use result somehow
    }
};

By the way, take a note that they may implement compute() as bool compute(const T1 i1, const T2 i2);, where T1 and T2 can be any integer or floating type.

A base class doesn't know anything about its derived classes, so there's no real way you can assert anything. In many cases, you can work around this by making the base class a template which takes the derived class as an argument. That won't work here, however, since you want a static check resulting in a compile time error immediately when you derive, and at that moment, the derived class isn't a complete type, and you can't use any of the functions in it (not even in a sizeof expression).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top