0

I'm trying to implement a C++ program that, given a list of elements, prints out unique elements from the list.

I know C a lot better than C++, but I am starting out on C++ practically (coding) only now.

I've only read up on C++ concepts what templates are and I'm comfortable with function templates but I just read up on class templates and I think I'm getting confused as to where to use which one, as applied to the scenario below.

Here's what I've written so far (*note that the function isUnique is supposed to be doing something else but I'm writing just verifiable actions inside it for now):

cppArrays.h

#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;

template <class T> class cpparray{
private:
    int size;
    vector<T> elems;
public:
    cpparray(int);
    ~ cpparray();
    int isUnique(T arr);
};


template <class T> cpparray<T>::cpparray(int size)
{
    vector<T> elems(size);
    cout << "Object created with size " << elems.size()<< "\n"<< endl;
}
template <class T> cpparray<T>::~cpparray()
{
    cout << "Object del\n" << endl;
}

template <class T> int cpparray<T>::isUnique(T arr)
{
    return arr.size();
}

cppArrays.cc

#include "cppArrays.h"

int main()
{
    cpparray<int> a(10) ;
    //a.push_back(1);
    //a.push_back(2);
    //cout << a.size() << a.begin() << a.end() << endl;
    int b = isUnique(a);
    return 0;
}

Details:

[1] I'm trying to use templates, because I want my vector to be able to be instantiated with any data type - char/float/int.

[2] I realize that in using a class template, by calling

cpparray<int>a(10);

I end up declaring an object a of class "cpparray" whose type is Integer. Is this correct? If yes, then a.push_back(1) wouldn't work because it doesn't refer to the member variable but the object itself and hence it's understandable I'll get a compile time error saying no member named push_back in cpparray.

But this is making it even more difficult for me to

[1] understand when to use class template as opposed to function template,

[2] How do I initialize this vector in the template class and work with it, given my objective?

Raaj
  • 1,180
  • 4
  • 18
  • 36
  • `push_back` should exist as a member function of `array`. Then [this](http://stackoverflow.com/questions/926752/why-should-i-prefer-to-use-member-initialization-list). `elems` in your constructor is a local instance. – LogicStuff Jul 10 '16 at 23:18
  • Precisely. But I'm trying to use the std container vector, but I'm messing up the part where I try to generalize the class array to work with vector of any type of data. – Raaj Jul 10 '16 at 23:22
  • I would say you're messing up the part that comes before templates in a C++ introductory book in the case of that initialization attempt. And asking *"class template vs function template"* is a bit like *"class vs function"*. – LogicStuff Jul 10 '16 at 23:24
  • 2
    @Raaj -- Please don't call your home-made class `array`. There already is a `std::array` class in C++. – PaulMcKenzie Jul 10 '16 at 23:26
  • @PaulMcKenzie noted. Will call it something else. Thanks! That wouldn't still help me figure out what I'm doing wrong :/ – Raaj Jul 10 '16 at 23:27
  • @Raaj -- You skipped the important chapter in your C++ book that discusses the "member initialization list" of the constructor. You failed to use it to initialize the vector member. All you did in your constructor was create a temporary vector called `elems` -- you didn't change anything to your member variable `elems`. – PaulMcKenzie Jul 10 '16 at 23:28
  • @Raaj -- Also, get rid of the `size` member variable. It is not necessary, as a `vector` knows its own size by calling the `size()` member function. Carrying around unnecessary size variables only can lead to bugs occurring. – PaulMcKenzie Jul 10 '16 at 23:34
  • Possible duplicate of [vector as a Data Member in C++](http://stackoverflow.com/questions/20849484/vector-as-a-data-member-in-c) – smac89 Jul 11 '16 at 00:17

2 Answers2

2

Your constructor should use initialization list to init members,

like this:

template <class T> array<T>::array(int sz) :  size(sz), elems(sz)
{
    cout << "Object created with size " << elems.size()<< "\n"<< endl;
}

What you did is to declare the vector as local in the constructor, init it to size, and the local vector was destroyed at the end of block.

SHR
  • 7,940
  • 9
  • 38
  • 57
2

Use a class template when you need a generic type that has compile-time variable properties. Template parameters can be types and constants, e.g.

template<typename T, size_t Size>
class MyArray {
    T elements_[Size];
public:
    MyArray() {}
    // ...
};

Use a function template when wish to write a generic function that can be applied to various types/parameters:

#include <cstdio>
#include <iostream>

template<size_t BufSize, typename... Args>
int strprintf(char(&buf)[BufSize], const char* fmt, Args&&... args)
{
    static_assert(BufSize > 0, "Buffer too small");
    static_assert(BufSize < (1 << 31), "Buffer too large");
    return snprintf(buf, BufSize, fmt, std::forward<Args>(args)...);
}

int main() {
    char buf[16];
    int printed = strprintf(buf, "hello world %s so long", "oversized load");
    std::cout << buf << "\n";
}

http://ideone.com/SLUQX3

The above is an example of how you can replace one of those old vsnprintf forwarding printf-type functions; doing all the legwork at compile time makes it drastically more efficient.

BufSize can be deduced by the compiler because the type of buf is char[16]; it can capture the source by reference, the type is char and the array size - the template variable - is 16.

It's also possible to have a templated member function of a templated class:

template<typename T>
class Foo {
    T t_;
public:
    Foo() : t_() {}
    Foo(const T& t) : t_(t) {}

    template<typename RhsT>
    bool is_same_size(const RhsT& rhs) {
        return t_.size() == rhs.size();
    }
};

This example will only work for instances when both T and RhsT have a size() member function, leading to the following:

Foo<vector<int>> fvi;
Foo<list<double>> fld;
fvi.is_same_size(fld);  // fine
Foo<int> fi;
fvi.is_same_size(fi);  // compiler error
kfsone
  • 23,617
  • 2
  • 42
  • 74