-2

I want to call a method on a template class, and I need a way to ensure that method will be on my template class.

The only way I know how to ensure a method is available on a class, is to derive the class from a pure virtual base class. This creates an enormous amount of overhead, as you can see in the code below.

Obviously, the interface is extraneous and unrelated to the explicit specialization of the templated class, which is actually driving the code in main.cpp. Am I just being old fashioned and clinging onto "interfaces", or is there a modern object-oriented approach to ensuring template classes are complete?

EDIT: To provide insight into the code below...

There is an interface, called "Interface", which has a virtual destructor and a pure virtual method called sayHi(). A inherits from Interface and implements sayHi(). A is then passed as a template into Template, which then calls sayHi() in its salutations() method. To further confuse things, a static method is the best solution for my problem. However, in order to use a base class as an interface to provide inheritance to my template class I could not have a static method, so you see two methods non-static to satisfy the virtual method and one static to satisfy my needs.

As I see it, there is no need of the interface other than to be organized in an object oriented since, and it causes a considerable amount of pain. Is there another way to get the sense of order provided by an interface, or is this type of thinking just obsolete?


main.cpp

#include "a.h"
#include "template.h"

int main (int argc, char * argv[]) {
    Template<A> a;

    a.salutations();

    return 0;
}

interface.h

#ifndef INTERFACE_H
#define INTERFACE_H

struct Interface {
    virtual
    ~Interface (
        void
    ) {}

    virtual
    void
    sayHi (
        void
    ) const = 0;
};

#endif

a.h

#ifndef A_H
#define A_H

#include "interface.h"

class A : public Interface {
  public:
    A (
        void
    );

    ~A (
        void
    );

    void
    sayHi (
        void
    ) const;

    static
    void
    sayHi (
        bool = false
    );
};

#endif

a.cpp

#include "a.h"

#include <iostream>

A::A (
    void
) {}

A::~A (
    void
) {}

void
A::sayHi (
    void
) const {
    return A::sayHi(true);
}

void
A::sayHi (
    bool
) {
    std::cout << "Hi from A!" << std::endl;
}

template.h

#ifndef TEMPLATE_H
#define TEMPLATE_H

template <class Interface>
class Template {
  public:
    void salutations (void);
};

#endif

template.cpp

#include "template.h"

#include "a.h"

template<>
void
Template<A>::salutations (
    void
) {
    A::sayHi();
    return;
}
Zak
  • 12,213
  • 21
  • 59
  • 105
  • @Praetorian From the post you linked: "*The question is incorrect. There is another portable way. The template class can be explicitly instantiated - as has been pointed out by other answers. – Aaron McDaid Aug 27 '12 at 11:42*". Which is precisely what I illustrated in the example code above. – Zak Feb 01 '15 at 09:24
  • 1
    It is not clear at all what you are trying to do. Please show code you *want* to work. – n. m. could be an AI Feb 01 '15 at 09:41
  • @n.m. The interface, is literally called "Interface", and has a virtual destructor and a pure virtual method called `sayHi()`. `A` inherits from `Interface` and implements `sayHi()`. `A` is then passed as a template into `Template` which then calls `sayHi()` in its `salutations()` method. There is no need of the interface other than to be organized in an object oriented since. – Zak Feb 01 '15 at 09:47
  • The template doesn't call the virtual function, it cannot do so because it has no object of type A. It calls a static function which is totally unrelated. The interface serves no purpose. Any class unrelated to `Interface` can happily define `sayHi` and be successfully used as a template parameter to `Template`. A class that does derive from `Interface` but does not define any static function can't. – n. m. could be an AI Feb 01 '15 at 09:54
  • @n.m. Exactly my point! So now, how do I bring order to the classes I'm passing into Template? Or, to put it in your words, how do I ensure a the class that is passed in as a template has happily defined `sayHi()`? – Zak Feb 01 '15 at 10:01
  • If you want to restrict your template to accept any class that has a *static* method, don't use any interfaces, they are useless in this case. Just call the static method. – n. m. could be an AI Feb 01 '15 at 10:02
  • If you want nicer error messages for the case of someone passing in a wrong class, use `std::static_assert`. There are lots of examples and howtos out there that cover just this use case. – n. m. could be an AI Feb 01 '15 at 10:06
  • @n.m. `std::static_assert` is great, these are things I'm looking for! Thank you. – Zak Feb 01 '15 at 10:20

1 Answers1

0

C++ is not Java. I do not know any way to say that the class or typename must be derived from another class.

It is really duck typing. Just use the methods and compiler will throw errors if they are not present. BTW, when you write

template <class Interface>
class Template {
  public:
    void salutations (void);
};

Interface is here the same as T would be : it does not require that the specialization used will be a subclass of class Interface.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • You can use `std::enable_if::value>::type` but this doesn't really make much sense. If we are already using dymaic polymorphism anyway, why use a template at all? – 5gon12eder Feb 01 '15 at 10:03
  • @5gon12eder I am not interested in using interfaces. The polymorphism is hardware related, and will be finalized at compile time. Can you expand on `std::enable_if...` in an answer? – Zak Feb 01 '15 at 10:04
  • @Zak Then your question is quite misleading because your code is using `virtual` all over the place. – 5gon12eder Feb 01 '15 at 10:05
  • @5gon12eder I am using `virtual` as minimally as possible in order for the code to compile. The point is to use an interface to ensure the methods are available, and I'm looking for better solutions. – Zak Feb 01 '15 at 10:07
  • There is lots of information available on [`std::enable_if`](http://en.cppreference.com/w/cpp/types/enable_if); search for SFINAE. Also see [this](https://stackoverflow.com/questions/28035703/sfinae-overload-operator-to-call-print-method-if-it-exists/28035809#28035809) question for checking whether a type has a certain function member. It is a bit messy but until we will get concepts in C++, this is the best we have. – 5gon12eder Feb 01 '15 at 10:09
  • "I do not know any way to say that the class or typename must be derived from another class." With `std::is_base_of`. – juanchopanza Feb 01 '15 at 10:12
  • @juanchopanza Can you formalize your comment into an answer? – Zak Feb 01 '15 at 10:13
  • 2
    @Zak No, because I am too lazy to figure out what exactly it is you are asking ;-) – juanchopanza Feb 01 '15 at 10:14
  • @5gon12eder I just looked up `std::enable_if` it is a great answer to my question! Thanks! – Zak Feb 01 '15 at 10:16
  • @Zak Open the documentation for `std::sort`. Look at the function declaration. It accepts two iterators. How does it ensure the things you are passing it are indeed itetators? What happens if you pass two `float`s or two `class A` objects that don't have any iterator functionality? Iterators normally don't have any virtual functions. – n. m. could be an AI Feb 01 '15 at 10:20
  • @Zak no, `std::enable_if` won't do anything useful for you. – n. m. could be an AI Feb 01 '15 at 10:21
  • @n.m. It led me to `type traits`, so it was a good answer. ;-) I am desperately trying to find a modern approach to type safety and good error messages. – Zak Feb 01 '15 at 10:27
  • You already have type safety. The modern approach to nice error messages is C++ concepts, but they are not a part of the language yet. The next best thing is static_assert. Type traits are very useful but actually only tangentially related to your question. They help building more generic solution, not more type-safe ones. – n. m. could be an AI Feb 01 '15 at 10:35
  • @n.m. First I want to say, "Thank you" for sticking with me on this. Can you give me a pointer to some documentation on "concepts"? I'm insanely interested, and I want to learn how to do this "the right way" even if it means losing a couple stackoverflow points. – Zak Feb 01 '15 at 10:40
  • @Zak [here](http://en.wikipedia.org/wiki/Concepts_%28C%2B%2B%29) is the original proposal described. The current proposal that's probably going to be implemented is called "concepts lite", just google it. – n. m. could be an AI Feb 01 '15 at 10:45