tags:

views:

72

answers:

3

I'm getting confused with implicit and explicit declarations. I don't know why you need to explicitly say or at certain times. For example,

In my main.cpp

#include <iostream>
#include "Point.h"

int main()
{
    Point<int> i(5, 4);
    Point<double> *j = new Point<double> (5.2, 3.3);
    std::cout << i << *j;
    Point<int> k;
    std::cin >> k;
    std::cout << k;
}

for Point<int> k. Why do I have to use the explicit declaration? I get compile errors otherwise. Or do I have it coded incorrectly in my Point.h file?

Point.h:

#ifndef POINT_H
#define POINT_H

#include <iostream>

template <class T>
class Point
{
public:
    Point();
    Point(T xCoordinate, T yCoordinate);

    template <class G>
    friend std::ostream &operator<<(std::ostream &out, const Point<G> &aPoint);

    template <class G>
    friend std::istream &operator>>(std::istream &in, const Point<G> &aPoint);

private:
    T xCoordinate;
    T yCoordinate;
};

template <class T>
Point<T>::Point() : xCoordinate(0), yCoordinate(0)
{}

template <class T>
Point<T>::Point(T xCoordinate, T yCoordinate) : xCoordinate(xCoordinate), yCoordinate(yCoordinate)
{}


template <class G>
std::ostream &operator<<(std::ostream &out, const Point<G> &aPoint)
{
    std::cout << "(" << aPoint.xCoordinate << ", " << aPoint.yCoordinate << ")";
    return out;
}

template <class G>
std::istream &operator>>(std::istream &in, const Point<G> &aPoint)
{
    int x, y;
    std::cout << "Enter x coordinate: ";
    in >> x;
    std::cout << "Enter y coordinate: ";
    in >> y;
    Point<G>(x, y);

    return in;
}

#endif
+7  A: 

For a class template, the template arguments must be specified explicitly.

For a function template, the template arguments can be inferred implicitly.

Point is a class, so explicit declaration is required.

KennyTM
Or in more general terms: function templates and class templates need to be instantiated before they can be used. Once that's done, you can actually use the instantiated function or class. Functions and classes require you provide the necessary parameters before they can be instantiated, but functions can deduce their template parameters from function parameters.
GMan
+2  A: 

Your operator>> is incorrect. You need to modify the value of aPoint:

template <class G>
std::istream &operator>>(std::istream &in, const Point<G> &aPoint)
{
    std::cout << "Enter x coordinate: ";
    in >> aPoint.x;
    std::cout << "Enter y coordinate: ";
    in >> aPoint.y;

    return in;
}

Also, it is definitely not standard for operator>> to do anything except read the data. So the next iteration would be:

template <class G>
std::istream &operator>>(std::istream &in, const Point<G> &aPoint)
{
    in >> aPoint.x;
    in >> aPoint.y;

    return in;
}

This is also not ideal because the output format differs from the input format.

R Samuel Klatchko
+1  A: 

I almost just edited a couple of extra details into KennyTM's answer, but what the heck:

For a class template, the template arguments must always be specified explicitly, or provided as default template arguments.

For a function template, the template arguments can usually be inferred automatically, though sometimes you need (or want) to specify them explicitly. For one fairly common example, consider a template like:

template <class T>
void func(T const &a, T const &b) { }

If you call this with arguments of two different types (say, int and double), and each type can convert to the other implicitly, the compiler can't normally decide which type to use. You can fix this by using casting to explicitly convert both arguments to the same type, or by specifying the template arguments explicitly:

func(1, 1.0);          // ambiguous, T could be int or double
func((double)1, 1.0);  // unambiguous
func<double>(1, 1.0);  // also unambiguous
Jerry Coffin