0

I have created a SinglyLinkedList template class using template <class T>. For example, if I enter "string" as my command line argument, I want to create SinglyLinkedList<string>* string_list = new SinglyLinkedList<string>();. If I enter "number" as my command line argument, I want to create SinglyLinkedList<string>* number_list = new SinglyLinkedList<string>();.

Is there a way that I can combine this in order to do something along the lines of:

SinglyLinkedList<>* list;
if (argv[0] == "string") {
    list = new SinglyLinkedList<string>();
} else if (argv[1] == "number") {
    list = new SinglyLinkedList<int>();
}

If I do this now, the first line throws an error invalid template code.

Is there a way to do this in C++11?

Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
Dan Levy
  • 3,931
  • 4
  • 28
  • 48
  • Polymorphism. Have your templated types all inherit from a single base class – Passer By Mar 06 '18 at 02:11
  • Or use [boost::any](http://www.boost.org/doc/libs/1_66_0/doc/html/any.html) or [std::any](http://en.cppreference.com/w/cpp/utility/any). Note that this is no different than if you wanted to use `vector` or `vector` in the same way. – PaulMcKenzie Mar 06 '18 at 02:13
  • One question is: Will it be useful to have one variable for both types of lists like that? If you actually want to do anything useful with the elements of those lists you'll need to know their type again. In one case you'll need string variables/function/values, in the other case the same for int. Having a "generic" list like that doesn't really help if you want to work with the elements it contains. – sth Mar 06 '18 at 02:39
  • @sth If I am understanding you correctly, I have a generic Node class that has a generic variable called value. Please take a look at my first comment below Ken Y-N's answer. – Dan Levy Mar 06 '18 at 02:42
  • @sth Are you saying that my best bet would be to create separate non-generic variables (one int and one string)? – Dan Levy Mar 06 '18 at 02:52
  • @DanLevy: My point is that when you for example want to insert an element into your list you'll have to have insert either `1` or `"one"`. So you'll need another `if` there. And if you then want to look at that list element you just created you'll need something that processes ints or something that processes strings.So another `if`. And then you have to convince the compiler that you are not actually trying to access ints as strings or the other way around, which is a problem when you just have a generic `SinglyLinkedList<>` that doesn't know what it contains. – sth Mar 06 '18 at 02:59

3 Answers3

1

Things will probably be easier if you put the whole list processing into a generic function:

template<typename Item>
void process_list() {
  SinglyLinkedList<Item>* list = new SinglyLinkedList<Item>();
  Item it;
  if (std::cin >> it) {
     list->push(it);
  }
}

This way you can do all your processing for generic items of type Item and only need to distinguish the types once when calling the function:

int main(int argc, const char **argv) {
    if (argv[0] == "string") {
        process_list<string>();
    } else if (argv[1] == "number") {
        process_list<int>();
    }
}
sth
  • 222,467
  • 53
  • 283
  • 367
  • Because I have to use C++ 11 for my course, I think that is the best answer in my case. I made my question easier to understand by using argv but I am actually using ifstream to input a file. In the process_list() method, is there a way that I can pass in a non-template variable. For example, void process_list(ifstream in_file)? When I do this, I can't call the method with the argument. It says "use of undeclared identifier process_list." – Dan Levy Mar 06 '18 at 05:12
  • That's an example of ad-hoc polymorphism of a kind. If that's all you need, then you might not need a templated class at all, just `process_int_list()` and `process_string_list()`. – Jive Dadson Mar 06 '18 at 05:32
  • For the specific project I am working on, the code for processing the date the string and int lists is almost identical. Becuase of this, I would like to use just one method. Is it possible to include a non-template parameter in a template method? @JiveDadson – Dan Levy Mar 06 '18 at 05:42
0

Template instantiations are independent classes, so there is no common base class, but one way is to address this is to explicitly define a base class:

// Empty base class
class SinglyLinkedBase {};

template <typename T>
class SinglyLinkedList : public SinglyLinkedBase
{
    // As before
};

SinglyLinkedBase* list;
if (argv[0] == "string") {
    list = new SinglyLinkedList<string>();
} else if (argv[1] == "number") {
    list = new SinglyLinkedList<int>();
}

In addition, Boost::any or std::any (if you have a C++17 compiler) can probably do this without the dummy base class.

Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
  • So, I assume I implement the base class as an abstract class here. If I do that, how can I set up the pure methods in the base class so that I can use generics in the SinglyListList (child) class? Right now I have a generic Node class. If I create a NodeBase class, I still run into a problem with the Node holding a generic value aka "T _value;" – Dan Levy Mar 06 '18 at 02:39
0

You are using the run-time type determination.

Under such condition, if you still want to use the same variable "list", its type should be an abstract base pointer. Just using the "type erasing" trick shown in How do boost::variant and boost::any work?

Or just as shown in sth's answer, you may have two different-type local versions in different template instantiations.

If you want to pass non-template parameter, remember to use

process_list<string>(in_file) instead of process_list(in_file)

whitebob
  • 48
  • 6