tags:

views:

604

answers:

7

When I'm writing a function in a template class how can I find out what my T is?

e.g.

template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (typename T == int)
}

How can I write the above if statement so it works?

+9  A: 

Define it explicitly, e.g.:

template <>
ostream& operator << (ostream &out,Vector<int>& vec)
{
}
Artem Barger
Remove `template <int>` and it'll be fine.
avakar
thanks, for pointing on mistake, I didn't touched C++ for a while, I didn't remember how to write specialization for templates.
Artem Barger
No need for a template specialization. Prefer an overload over Function template specializations. The latter can be surprising sometimes. (There's a GOTW on the subject)
jalf
+1 Template specialization is the way to do it.
Magnus Skog
+18  A: 

Something like this:

template< class T >
struct TypeIsInt
{
    static const bool value = false;
};

template<>
struct TypeIsInt< int >
{
    static const bool value = true;
};

template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
    if (TypeIsInt< T >::value)
    // ...
}
Charles Bailey
+7  A: 

This way.

ostream & operator << (ostream &out, Vector<int> const & vec)
{
    // ...
}

The compiler will choose this function over the function template if you pass Vector<int>.

Edit: I found this article, which attempts to explain why to prefer overloading to template specialization.

avakar
+1 because its a great article but if you read "Moral #2" you should have made it a class template specialization. I can't believe all the others just ignore this article or didn't read "Exceptional C++ Style"
TimW
+1: Always prefer overloading over specialization.
Johannes Schaub - litb
+7  A: 

The easiest way is to provide a template specialisation:

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

template <typename T> struct A {
};

template <typename T > 
ostream & operator <<( ostream & os, A<T> & a  ) {
    return os << "not an int" << endl;
}


template <> 
ostream & operator <<( ostream & os, A<int> & a  ) {
    return os << "an int" << endl;
}

int main() {
    A <double> ad;
    cout << ad;
    A <int> ai;
    cout << ai;
}
anon
You have a semicolon after the second function template definition. Also, why do you prefer template specialization to an overload?
avakar
Weird - that exact code compiled with g++ with no errors!
anon
<Exceptional C++ Style> If you're writing a primary function template that is likely to need specialization, prefer to write it as a single function template that should never be specialized or overloaded, and then implement the function template entirely as a simple handoff to a class template containing a static function with the same signature. Everyone can specialize that both fully and partially, and without affecting the results of overload resolution.
TimW
+1 Here as well.
Magnus Skog
Neil, I see you've edited the answer, but instead of removing the semicolon, you've added another one. :) I'm also still curious as to why you prefer function template specialization to an overload.
avakar
Ah OK - my brain was a bit slow there. The semicolons are of course perrfectly legal. As to my preferences - in this matter I honestly don't have any.
anon
@Neil: When in doubt, why not follow GOTW advice? ;) Avakar linked to one suggesting to prefer overloads when possible. :)
jalf
I don't think the semicolons are legal after function-definition, at least in C++03.
avakar
overloading should be the way to go. explicit specialization for functions is both unnecessary limiting and causing lots of pits
Johannes Schaub - litb
@avakar, they are only optional after member function definitions (within class), but not as a normal function definition (likewise, they aren't legal after template declarations, regardless of whether they appear in class or not).
Johannes Schaub - litb
litb, you're right about member functions. Weird. I wonder why this was allowed, especially since it's allowed so explicitly (`member-declaration = ... | function-definition ;opt`).
avakar
@avakar, @litb -My understanding was that a semi-colon after a function definition would behave as an 'empty statement' and not do anything, thus is legal but not required.
CiscoIPPhone
@CiscolPPhone, a statement cannot appear outside of a function. Thus that would be invalid too.
Johannes Schaub - litb
It's worth to mention that C++0x adds "empty declarations", which allows you to put semicolons also after free function definitions
Johannes Schaub - litb
A: 

C++ templates don't work this way. The general idea of templates is express somethings which is common for a lot of different types. And in your case you should use template specialization.

template<class T> ostream& operator<< (ostream& out, const vector<T>& v)
{
    // your general code for all type
}
// specialized template
template<> ostream& operator<< <int>(ostream& out, const vector<int>& vec)
{
    // your specific to iny type code goes here
}

Then C++ compiler will call this function when you use int type and general implementation for any other type

std::vector<int> f(5, 5);
std::cout << f;
Serge
+5  A: 

TypeID is never a good idea. It relies on RTTI. By the way here is your answer :http://www.parashift.com/c++-faq-lite/templates.html#faq-35.7

siddhant3s
So RTTI is bad now? And typeid is known at compile-time.
GMan
what's the problem with RTTI?
Dave
typeid is quite slow. Template specialization is done at the compile time while typeid costs you runtime. Make your way.Ref:http://www.velocityreviews.com/forums/t279741-how-do-you-know-datatype-when-using-templates.html
siddhant3s
How can something computed compile-time be slow? typeof(T) is known at compile time, as is typeof(int), and so on. Therefore, it will reduce to if (true), else if (false), etc... then the dead code will be removed, as will the if (true) check.
GMan
RTTI is bad when it can be avoided. @GMan, that depends on compiler optimizations. There's no guarantee it'll happen at compile-time. Why not go for the solution that is guaranteed to be compile-time? Especially when it is also more conventional and less surprising to people reading the code? Of course as a bonus, RTTI may be disabled by compiler switches, so you may not be able to rely on it being there.
jalf
Like I said, typeid() is determined at Runtime. While template instantiation is done at compile time. Hence, typeid is not a good thing to do.Who told you typeid is known at compile time? Do you have any references?I am pretty sure that typeid is known at runtime. Here is a reference: http://msdn.microsoft.com/en-us/library/fyf39xec.aspx
siddhant3s
typeid of a compile-time known type can be optimized out like I was suggesting. jalf is right in saying it depends on compiler optimizations, but if a compiler can't optimize that out, it might time to move on to a modern compiler...This all said, the way the OP described his problem, typeid() allows him to place the if-statements exactly how he wanted. I personally would specialize templates. I just never understood the whole "RTTI is evil" mentality.
GMan
What is up to compiler is not the issue. When I write a code, I would consult the standards not try it with my-favorite-compiler.The OP created the construct because he was confused how he best can describe his problem. Use of TypeID should be as minimum as possible. Up till now, we all suggest the OP to use template specialization instead. I am not sure why there is a green box on a answer with -2 votes. TypeID() is evaluated at runtime(as per standard).
siddhant3s
How can typeid(int) not be optimised at compile time? You'd have to deliberately go out of your way to write a compiler where integers are stored as a generic object along with type information. In which case you're reading tealeaves to predict the performance of particular code on that compiler. It's only pointer and reference types where typeid has to be calculated at runtime, because there may be runtime polymorphism in play.
Steve Jessop
@siddhant3s: funny that you say consult the standard, but actually refer to MSDN, which is the documentation of your-favourite-compiler. It says, "If the expression is neither a pointer nor a reference to a base class of the object, the result is a type_info reference representing the static type of the expression. "
Steve Jessop
typeid(T) is surely not determined at compile time. When you say typeid(T)==typeid(int) you have a runtime overload to calculate typeid(T) if T not happens to be a built in type.
siddhant3s
I just got the reference on a quick google search. VC++ is not my compiler, I am a native Linux User and hence GCC is what I use.
siddhant3s
Actually, I've just clocked that the accepted answer (which presumably is what you object to) is using typeid with a type, not with an object. See 5.2.8:4 in the standard. So typeid(T) certainly is determined at compile time. The type is T, not any sub-type: there is no polymorphism because there are no objects. The accepted answer still relies on the compiler to do compile-time evaluation of constant expressions, and dead code removal.
Steve Jessop
Johannes Schaub - litb
@litb: that seems to be what happens on gcc (with -O3). The typeid expressions are emitted as constant fixups, (external for int, internal for a user-defined type), then the call to the comparator is an external reference, so the dead case is not removed. If the comparator call were inlined maybe we'd be in business, but it isn't with the compiler options I used. I wonder if there's anything I could statically link against that would help.
Steve Jessop
+7  A: 

Simplest, most general solution: Just write a plain old overload of the function:

ostream& operator << (ostream &out,Vector<int>& vec)
{
// Your int-specific implementation goes here
}

This assumes that the int and non-int versions don't have much code in common, as you have to write two separate implementations.

IF you want to use one common implementation of the function, with just an if statement inside that differs, use Charles Bailey's implementation:

template< class T >
struct TypeIsInt
{
    static const bool value = false;
};

template<>
struct TypeIsInt< int >
{
    static const bool value = true;
};

template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
    if (TypeIsInt< T >::value) {
      // your int-specific code here
    }
}

In general, don't use typeid if you don't need to.

jalf