Aquasylum
Aquasylum

Reputation: 59

How to create a vector of Templates?

Im trying to build a vector of type template but keep getting an error

 template<class T>
 struct s{

    T val;

    public:
        s(T a)
        {
            val = a;
        };

        friend ostream& operator<<(ostream& os, const T& a);
 };

 template <typename T>
 ostream& operator<< (ostream& os, const T& a){
     return os << a.val;
 }

int main()
{
    s <double> names(4) ;
    s <int> figure(7);
    s <string> word();
    s <vector<int>*> arrays();
    cout << names << endl;
    cout << figure << endl;
    cout << arrays << endl;
    return 0;
}

I keep receiving the same error -

request for member 'val' in 'a', which is of non-class type 's<std::vector<int>*>()'|

Any advice will be greatly appreciated

Upvotes: 0

Views: 309

Answers (3)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48457

s <vector<int>*> arrays();

This does not instantiate an object, it declares a function that returns s<vector<int>*>, and as a consequence:

cout << arrays << endl;

Tries to print out a function pointer by instantiating your templated operator<<:

template <typename T>
ostream& operator<< (ostream& os, const T& a){
    return os << a.val;
}

with:

T = s<vector<int>*>(*)();

and so, a pointer to function a does not have the .val field which triggers the error.

Upvotes: 2

T.C.
T.C.

Reputation: 137315

s <vector<int>*> arrays();

Declares a function named arrays taking no arguments and returning a s<vector<int>*>. Remove the redundant parentheses or replace them with {} for C++11. Of course, your s doesn't support default construction, so you need to give it a default constructor - which can be as simple as giving the constructor a default argument:

    s(T a = T())
    {
        val = a;
    }

and it's better to use the member initialization list instead of assignment and take a const ref instead of by value, since T can be large:

    s(const T& a = T()) : val(a) { }

In C++11, you should take by value and move a into val instead:

     s(T a = T()) : val(std::move(a)) { }

Also,

 template <typename T>
 ostream& operator<< (ostream& os, const T& a){
     return os << a.val;
 }

would match everything under the sun. Better to match s only:

 template <typename T>
 ostream& operator<< (ostream& os, const s<T>& a){
     return os << a.val;
 }

Finally,

friend ostream& operator<<(ostream& os, const T& a);

befriends (and declares) a simple function rather than a function template. To befriend the template operator << as modified above:

    template <typename U>
    friend ostream& operator<<(ostream& os, const s<U>& a);

Or even better, remove the template operator and define the friend function inline (inside the class definition) instead:

    friend ostream& operator<<(ostream& os, const s<T>& a){
        return os << a.val;
    }

This is more compact, and also limits friendship to the matching version of operator <<, rather than all instantiations of the template.

Demo.

Upvotes: 2

grzkv
grzkv

Reputation: 2619

The whole problem is that this

ClassName InstanceName();

is not creating an instance of ClassName using default constructor, but declares a function. In order to do what you wanted (and I presume that is to create instances with default constructors) use syntax

ClassName InstanceName;

So, in order to fix your errors, change

s <string> word();
s <vector<int>*> arrays();

to

s <string> word;
s <vector<int>*> arrays;

and add a default constructor to your class s.

Upvotes: 1

Related Questions