ejang
ejang

Reputation: 4062

C++ Calling functions with different signatures, depending on type

I'm wondering what is a good design pattern is for the following scenario. Three questions:

1) I have a templated "Container" class for subclasses of "Derived". I want to be able to store different kinds of template objects (of either type A or B, both subclasses of Derived) in a vector. How to do this?

2) I have a template-specific function "func" that operates on Containers and has a variable number of arguments, depending on whether the template type of Container is A or B. What's a good way to check template types at runtime to call the appropriate function?

3) Do templates even make sense for this use case?

#include <iostream>
#include <string>
#include <vector>
#include <memory>

using namespace std;

struct Derived {};

struct A : Derived { 
    int x; 
    A(int x) : x(x) {}
};
struct B : Derived { 
    bool y; 
    B(bool y) : y(y) {}
};

template <typename T>
struct Container
{
    T item;
    Container(T i) : item(i) {}
};

// definition of a template function for type a, with specialization
void func(Container<A> c, int a, int b) {
    cout << "update for A called" << endl;
}

void func(Container<B> c, bool x) {
    cout << "update for B called" << endl;
}

int main(int argc, char const *argv[])
{
    Container<A> * foo = new Container<A>(A(1));
    Container<B> * bar = new Container<B>(B(true));
    // test that func() works
    func(*foo,1,2);
    func(*bar,false);

    vector< Container<Derived>* > vec;

    // this does not work
    vec.push_back(unique_ptr< Container<Derived *> >(foo));
    vec.push_back(unique_ptr< Container<Derived *> >(bar));

    for (Container<Derived>* d : vec) {
        // how to call the proper func(d)?
    }
    return 0;
}

Upvotes: 0

Views: 553

Answers (1)

Peter
Peter

Reputation: 36597

1) You can store pointers to A (type A *) or pointers to B (type B *) in a std::vector<Derived *>, because Derived is a base for both A and B. It is not possible to store a Container<A> and a Container<B> into the same vector, because there is no inheritance relationship between them. This is also (indirectly) the reason that converting foo and bar to unique_ptr<Container<Derived *> > is being rejected by your compiler.

2) Your func() is not a "template specific function". It is not even a templated function. It is a function that is overloaded, with one variant that accepts two arguments, and one variant that accepts three.

3) Given that your code is invalid, it is not possible to infer what your use case is. Given that you are trying to convert objects to unrelated types, my guess is that your use case does not make sense in C++, let alone using templates for it.

Also, don't use Java (or whatever other language you are thinking in) techniques in C++, because they do not work the same way. Specifically;

Container<A> * foo = new Container<A>(A(1));
Container<B> * bar = new Container<B>(B(true));
func(*foo,1,2);
func(*bar,false);

is unnecessary. It is used in Java for various reasons that are invalid in C++, even if the code compiles. Instead, do this;

Container<A> foo A(1);
Container<B> bar B(true);
func(foo,1,2);
func(bar,false);

This is valid and safe C++ (and will not work in Java, but that's another story).

Upvotes: 1

Related Questions