6

I am having problem with overloading operator<< for a template class. I am using Visual Studio 2010, and here is my code.

#ifndef _FINITEFIELD
#define _FINITEFIELD
#include<iostream>

namespace Polyff{
    template <class T, T& n> class FiniteField;
    template <class T, T& n> std::ostream& operator<< (std::ostream&, const FiniteField<T,n>&);

    template <class T, T& n> class FiniteField {
    public:
            //some other functions
    private:
        friend std::ostream& operator<< <T,n>(std::ostream& out, const FiniteField<T,n>& obj);
        T _val;
    };

    template <class T, T& n>
    std::ostream& operator<< (std::ostream& out, const FiniteField<T,n>& f) {
        return  out<<f._val;
    }
    //some other definitions
}
#endif

In main I just have

#include"FiniteField.h"
#include"Integer.h"
#include<iostream>
using std::cout;
using namespace Polyff;
Integer N(5);

int main () {

    FiniteField<Integer, N> f1;
    cout<< f1;  
}

where Integer is just a wrapper of int with some special functionality I need.

However, when I compile the above code, I got error C2679, which says binary '<<' : no operator found which takes a right-hand operand of type 'Polyff::FiniteField<T,n>' (or there is no acceptable conversion)

I have also tried to remove the parameters in the friend declaration so the code becomes:

friend std::ostream& operator<< <> (std::ostream& out, const FiniteField<T,n>& obj);

But this produce another error: C2785: 'std::ostream &Polyff::operator <<(std::ostream &,const Polyff::FiniteField<T,n> &)' and '<Unknown>' have different return types

so I am wondering how should I change the code so it compiles and why? Thanks!

------------------------- edited on 2012.12.31 ---------------------------

The code compiles with g++ now. Here is the github repository.

Rohit Vipin Mathews
  • 11,629
  • 15
  • 57
  • 112
tgeng
  • 1,768
  • 2
  • 15
  • 20
  • 1
    Though I'm not entirely sure what the T& is being used for, I'm not sure it matters. I tried your first code list with just `Polyff::FiniteField obj`, where N was a global `int`. It worked correctly (step-debugged to make sure) when I then `cout << obj << endl;`. Could it be a problem with your Integer class ? (by the way, using LLVM 4.1 on Mac OS X 10.8.1). – WhozCraig Dec 31 '12 at 08:43
  • Thanks for this advice. I just tested with int and it still doesn't work. However, when I tried to compile my code with g++ compiler, everything works fine, and so is my Integer wrapper class. Is this some bug with vs2010 compiler?! By the way, the parameter "T& N" is the upper bound for that finite field built on the integral domain it's based on. If you don't know what I am talking about and find it annoying interesting, you can find more about it if you search for "finite field". – tgeng Dec 31 '12 at 13:15
  • 2
    Clang++ and G++ both compile it OK (after adding a definition for `Integer` and default constructor for `FiniteField`, which you should have included to make the code complete and self-contained). N.B. `_FINITEFIELD` is a [reserved name](http://stackoverflow.com/a/228797/981959), pick a different macro for your include guard. – Jonathan Wakely Dec 31 '12 at 15:04
  • Thanks for the advice, I have put the link to the github repository with all the code at the end of the original post. – tgeng Jan 01 '13 at 02:21
  • If you remove in the friend function, you also need to remove it after `FiniteField`. This code just works with g++ too, the problem must be elsewhere. You could also update your code according to what @JonathanWakely says. – Barney Szabolcs Jan 03 '13 at 12:59
  • 2
    If you run with Polyff::operator<<(std::cout,f1); it gives message: could not deduce template argument for 'n', that might be a clue – Vasaka Jan 04 '13 at 15:16
  • 1
    That would be wired since `g++` is able to deduce how to refer to `operator<<`. I think I will just consider this to be a bug of VS2010 compiler. By the way, this program is just my tiny trial of C++ template, not any part of a serious project. Thanks for everyone 's help! – tgeng Jan 05 '13 at 00:15

3 Answers3

1

This seem to work as expected:

namespace Polyff{
  template <class T, T* n> class FiniteField;
  template <class T, T* n> std::ostream& operator<< (std::ostream&, const FiniteField<T,n>&);

  template <class T, T* n> class FiniteField {
  public:
    //some other functions
  private:
    friend std::ostream& operator<< <T,n>(std::ostream& out, const FiniteField<T,n>& obj);
    T _val;
  };

  template <class T, T* n>
  std::ostream& operator<< (std::ostream& out, const FiniteField<T,n>& f) {
    return  out << f._val.n; // I added the field of my Integer class
  }
  //some other definitions
}


struct Integer{
  Integer() : n(0){}
  Integer(int nn) : n(nn){}
  int n;
};

using std::cout;
using namespace Polyff;
Integer N(5);

int main () {
  FiniteField<Integer, &N> f1;
  cout<< f1;  
}

I just replaced the reference by the pointer of your object in the template arguments, since a pointer to a global object (static or not) is an information known at compile-time (or at least link time). I am not aware of the language accepting references.

Note that in this example, 0 will be printed because it corresponds to the default construction of _val.

Raffi
  • 3,068
  • 31
  • 33
0

I tried to compile your code on my Visual C++ 2010. I got the same error as you did.

There are actually two things that Visual did not like in your code:

  1. N is not a compile time constant (which is right, no?).
  2. The problem is then to take the reference of a compile time constant. So, you should replace "T& n" by "T n" in all your template arguments.

That made the job for me!

Dr_Sam
  • 1,818
  • 18
  • 24
  • actually non-type parameters can also be an address of a variable or function with external linkage, and such parameters participate in the deduction. looks like a problem in VC – Vasaka Jan 04 '13 at 15:45
  • Thanks for your answer! However I do think the reference to `N` is a compile time constant since the object is allocated in static memory. Otherwise, g++ shouldn't be able to compile, either. As to the second comment, did you use `int` as `T` when you switch `T &n` to `T n`? – tgeng Jan 05 '13 at 00:10
  • Here is what I did: replace Int by int (not T by int) and got the error reported. Then, I removed the "&" in the template parameters. VC complains that N is not a compile time constant. Then I defined a macro to replace N and it compiled. I reput the "&" in the template parameters and VC complains about taking the reference. So, complain 2 of VC was actually conditioned by the use of the macro (I should have been more precise on that, sorry). – Dr_Sam Jan 05 '13 at 14:17
  • Thank you for your reply. Are you proposing a work around for this issue? Or, I still don't understand how that explains the behavior of VC compiler. – tgeng Jan 07 '13 at 13:23
0

You should just replace the reference with plain variable (T n instead of T& n).

7890
  • 91
  • 1
  • 6