-2

I am trying to create abstract class which is a template for another classes. Is it possible to create "flexible" template?

Several classes will inherit from this one, all of them will have the functions with the same name, but with different arguments. The abstract class is "Interface" of inheritance classes - I will use pointer of this one to manage another.

For example we have two classes: A and B. find method of A class needs only type1 type, but the same method of B class needs type1 and type2 types.

This is how I am creating classes that inherit from template:

class A : public Repository<int> {
   public void find(int) override; };


class B : public Repository<int, float> {
   public void find(int a, float b) override; };

Its all about the part after public keyword. I don't want to type <int, float> to all classes.

I there any way to overload(?) the template<typename type1, typename type2> and the function?

The code of the abstract class.

#ifndef REPOSITORY_HPP
#define REPOSITORY_HPP

#include <string>

//template<typename type1>
template<typename type1, typename type2> 
    class Repository
{
    protected:
        typeSTRING name;

    public:

        virtual void find(type1) = 0;
        //virtual void find(type1, type2) = 0;
};

#endif
KKMKK
  • 87
  • 2
  • 10
  • this sounds like a case for old fashioned overloading, no need for templates – pm100 Jan 23 '18 at 16:45
  • @pm100 I have to use templates. – KKMKK Jan 23 '18 at 16:46
  • So you want to write `class A : public Repository` and have `A::find(int)` be detected to deduce that `Repository` should be used? – Quentin Jan 23 '18 at 16:46
  • @Quentin I can write whole `class A : public Repository` But I want the program to use only the `Repository::find(type1)` – KKMKK Jan 23 '18 at 16:50
  • 1
    " I have to use templates" - why? –  Jan 23 '18 at 16:53
  • @KKMKK I don't get what you mean by "use only `Repository::find(type1)`". If that's the only function provided by `Repository`, surely that'd do it. – Quentin Jan 23 '18 at 16:53
  • Read Andrei Alecsadrescu - Modern C++ Design and Aleksey Gurtovoy - C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost. – Minor Threat Jan 23 '18 at 16:54
  • @NeilButterworth Its a part of my homework. – KKMKK Jan 23 '18 at 16:54
  • @Quentin But in this case I am forced to write ` ` after `public` keyword in all classes. – KKMKK Jan 23 '18 at 16:57
  • Coming at it from another way: if you declare `template class Repository`, and in there `virtual void find(Args...) = 0;`, then you'll get the bare minimum for your `A` and `B` classes to compile as-is. Is that what you're looking for, or is something missing? – Quentin Jan 23 '18 at 16:57
  • @Quentin Yes, but I will be forced to write `: public Repository`, not just `: public Repository`, – KKMKK Jan 23 '18 at 17:01
  • @KKMKK no, you'd write (for example) `: public Repository` and then you can override `find(float)`. Which is exactly what you did in `A` and `B`. – Quentin Jan 23 '18 at 17:03
  • @Quentin No, if my template is: `template`, I need to write for example ` : public Repository` in all classes. I am trying to avoid that. If my class needs only one type, I want to write , for example: ` : public Repository`. – KKMKK Jan 23 '18 at 17:08
  • 1
    @KKMKK that's exactly what `Args...` buys you. It means "zero, one or more parameters". See *parameter pack* and *variadic template*. – Quentin Jan 23 '18 at 17:09

2 Answers2

4

You would need variadic template in base class, i.e

#include <iostream>

template <typename ... Args>
class Interface
{
  public:
    virtual void find(Args... args) = 0;
};

class Impl1 : public Interface<int>
{
  public:
    void find(int value) override
    {
      std::cout << "found" << value << std::endl;
    }
};

class Impl2 : public Interface<int, float>
{
  public:
    void find(int value, float other_value) override
    {
      std::cout << "found" << value << " " << other_value << std::endl;
    }
};

int main()
{
  Impl1 impl1 {};
  impl1.find(5);

  Impl2 impl2 {};
  impl2.find(5, 10.2);
}
AdvSphere
  • 986
  • 7
  • 15
  • This solution provides another problem. What if my template has more then one method, for example: `virtual type1 add(type1, type2) `? – KKMKK Jan 23 '18 at 17:40
  • If I understand correctly what you are saying, then add that method to your derived implementation with two types. Where that derived implementation can override for `find(type1)` and `add(type1, type2)`. – AdvSphere Jan 23 '18 at 17:49
  • @AdvSphere Ok, but how to add in `Interface` method of `Args` type? – KKMKK Jan 23 '18 at 17:53
1

To complement the below comment from @KKMKK, this is how you can get an specific type from Args... (from: get the Nth type of variadic template templates?):

template <typename ... Args>
class Interface
{
  public:
    using FirstType = typename std::tuple_element<0, std::tuple<Args...> >::type;

    virtual void add(FirstType) = 0;
    virtual void find(Args... args) = 0;
};

class Impl2 : public Interface<int, float>
{
  public:
    void add(int value) override
    {
      std::cout << "found" << value << std::endl;
    }
    void find(int value, float other_value) override
    {
      std::cout << "found" << value << " " << other_value << std::endl;
    }
};

int main()
{
  Impl2 impl2 {};
  impl2.add(5);
  impl2.find(5, 10.2);
}
AdvSphere
  • 986
  • 7
  • 15