-
October 16th, 2011, 02:35 PM
#1
problem for defining template class
Hi all:
I tried to define a template class which contains a member function. This member function has an argument whose type is the typename T.
Code:
template <typename T1>
class A
{
public:
A() {}
~A() {}
void memFunction( T1 arg1 )
{
// if arg1 is not a pointer, then implement the following line
arg1.itsMemberFunc();
// If arg1 is a pointer, then implement this line
arg1->itsMemberFunc();
}
};
In an application, I will apply the template and the member function.
Code:
int main()
{
A<AnotherClass> aDouble;
AnotherClass var1;
aDouble.memFunction( var1 );
A<AnotherClass*> anotherClass;
AnotherClass* var2 = new AnotherClass;
anotherClass.memFunction( var2 );
return 0;
}
You may have found that the template won't be compiled as for the line
aDouble.memFunction( var1 ); in main(), "arg1->" can't be recoginised.
So how can I solve this problem? THank you very much.
-
October 16th, 2011, 04:28 PM
#2
Re: problem for defining template class
Originally Posted by Xiaolei Shang
Code:
// if arg1 is not a pointer, then implement the following line
arg1.itsMemberFunc();
// If arg1 is a pointer, then implement this line
arg1->itsMemberFunc();
You can do this either by overloading the member function or by providing the class with a policy template argument to get a reference from a T.
However, this looks very strange, so I wonder what you are trying to achieve.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
October 16th, 2011, 05:07 PM
#3
Re: problem for defining template class
Originally Posted by D_Drmmr
You can do this either by overloading the member function or by providing the class with a policy template argument to get a reference from a T.
However, this looks very strange, so I wonder what you are trying to achieve.
Thank you D_Drmmr. But I don't quite get your idea. In your first option, when you say "overloading the member function", do you mean I may do following like normal class overloading functions?
Code:
void memFunction( T1* arg1 )
{
...
}
If so, this can't work because in main(), if you passed "AnotherClass*" type to memFunction(), the template class still look at it as T rather than T*. If my understanding is wrong, please correct me.
For your second option that you told me, I don't quite understand it. Would like mind to give me more details? Thank you very much.
Yes, this is strange. Actually, in my case, my template class takes a function pointer, and the memFunction() takes a pointer of AnotherClass. Then in the memFunction(), it will use the pointer to the function pointer to call some functions in AnotherClass. It's bit of messy. To simplify my question, my initial question should tell you what problem that I have basically.
-
October 16th, 2011, 06:53 PM
#4
Re: problem for defining template class
Originally Posted by Xiaolei Shang
You may have found that the template won't be compiled as for the line
aDouble.memFunction( var1 ); in main(), "arg1->" can't be recoginised.
So how can I solve this problem? THank you very much.
Read up on policies and templates. You need to tell the template how to call the function in question, and that is done by supplying an addition template parameter denoting how the template is supposed to "behave",
Here is a quick and dirty solution (not the best, but hopefully illustrates the point).
Code:
template <typename T>
struct PointerTraits
{
public:
void itsMemberFunc(T* arg)
{ return arg->itsMemberFunc(); }
};
template <typename T>
struct ValueTraits
{
public:
void itsMemberFunc(T arg)
{ return arg.itsMemberFunc(); }
};
template <typename T1,
typename theTraits = ValueTraits<T1> >
class A
{
public:
A() {}
~A() {}
void memFunction( T1 arg1 )
{
theTraits().itsMemberFunc(arg1);
}
};
struct foo
{
void itsMemberFunc();
};
int main()
{
A<foo> aDouble;
foo var1;
aDouble.memFunction( var1 );
A<foo*, PointerTraits<foo> > anotherClass;
foo* var2 = new foo;
anotherClass.memFunction( var2 );
return 0;
}
So if you're passing a pointer, you tell the template to use pointer semantics, otherwise use value semantics (value semantics are assumed by default). Note the trickery in the template -- instead of calling the member function directly, it calls the policy's function and the policy knows how to call the function, whether it is a value or pointer.
If you want a better real-life example, look at std::string. It really is a template:
Code:
typedef basic_string<char, char_traits<char> > string;
The second template parameter is a policy that tells how to collate, compare, characters.
Regards,
Paul McKenzie
-
October 17th, 2011, 07:18 AM
#5
Re: problem for defining template class
Originally Posted by Xiaolei Shang
If so, this can't work because in main(), if you passed "AnotherClass*" type to memFunction(), the template class still look at it as T rather than T*. If my understanding is wrong, please correct me.
Yes, but you did not explain how the class needs to use the template argument (and it's still not clear to me). In your example, there is no need for a class at all, so you might as well use an overloaded template function.
Originally Posted by Xiaolei Shang
For your second option that you told me, I don't quite understand it. Would like mind to give me more details? Thank you very much.
Just search for "C++ policy" and you'll find lots to read about it.
Originally Posted by Xiaolei Shang
Yes, this is strange. Actually, in my case, my template class takes a function pointer, and the memFunction() takes a pointer of AnotherClass. Then in the memFunction(), it will use the pointer to the function pointer to call some functions in AnotherClass.
If you are trying to write a function wrapper, have a look at boost::function or std::function if your compiler supports it.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
-
October 17th, 2011, 09:14 AM
#6
Re: problem for defining template class
Hi Paul:
Thank you very much for the detailed explanation. I really appreciate for this. I also get some idea about this.
I notice that in your main() function, you tell the template to use pointer or value when you define the object. However, if I did not tell the the template the passed argument is a pointer or value, Is there a way within the template to tell the passed argument is a poitner or value? For example:
Code:
int main()
{
A<foo> aDouble;
foo var1;
aDouble.memFunction( var1 );
foo* var2 = new foo;
// Here if we do not define the new object will be passed a pointer or
// value using the template policy argument. Is there a way within the template to sort this problem out by itself?
A<foo*> anotherClass;
anotherClass.memFunction( var2 );
return 0;
}
-
October 17th, 2011, 09:23 AM
#7
Re: problem for defining template class
Here's another method you could try. It uses specialised 'Value' template classes to return a reference to the argument passed. If the argument is a pointer then it is dereferenced.
Code:
// Returns a reference to the value.
template <typename T>
struct Value
{
T& operator()(T &t)
{
return t;
}
};
// Dereferences the pointer and returns a reference to the value.
template <typename T>
struct Value<T *>
{
T& operator()(T *t)
{
return *t;
}
};
template <typename T1>
class A
{
public:
A() {}
~A() {}
void memFunction( T1 arg1 )
{
// Call the member function.
Value<T1>()(arg1).itsMemberFunc();
}
};
class AnotherClass
{
public:
void itsMemberFunc()
{
}
};
int main()
{
A<AnotherClass> aDouble;
AnotherClass var1;
aDouble.memFunction( var1 );
A<AnotherClass*> anotherClass;
AnotherClass* var2 = new AnotherClass;
anotherClass.memFunction( var2 );
return 0;
}
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
October 17th, 2011, 10:57 AM
#8
Re: problem for defining template class
Originally Posted by Xiaolei Shang
You may have found that the template won't be compiled as for the line
aDouble.memFunction( var1 ); in main(), "arg1->" can't be recoginised.
So how can I solve this problem? THank you very much.
To me, it is very important to make the distinction between the parameter type, and the argument type relative to the parameter: To you want the behavior to change depending on the parameter T, or on the argument passed to the method?
IMO, different parameters should not change the behavior of your template from a generic point of view. If your template expects a class, then the correct solution is to simply not compile until the parameter is correct.
NOW, given a parameter, you can have the function take an argument of either pointer or type, of the parameter type.
Code:
#include <iostream>
template <typename T>
class string_operation
{
public:
static void do_it(T i)
{
std::cout << i << ": ";
}
static void print_it(T i)
{
do_it(i);
std::cout << "pass by value" << std::endl;
}
static void print_it(const T* i)
{
if(i == 0) return;
do_it(*i);
std::cout << "pass by pointer." << std::endl;
}
};
int main()
{
const std::string* pString = new std::string("I am an std::string");
const char* aChars = "I am a char*";
string_operation<std::string>::print_it(pString);
string_operation<const char*>::print_it(aChars);
}
Run this code, and observe how my argument of type "char*" is passed by value, yet my "std::string" is passed by pointer.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
October 18th, 2011, 01:57 AM
#9
Re: problem for defining template class
What JohnW is doing is called template partial specialization. It is a good way to write custom code for particular types that are sent in. It is used in template metaprogramming. If you are interested, you can find a lot of (maybe overwhelmingly so if you are new to C++) here:
http://www.boost.org/doc/libs/1_40_0...etaprogramming
Boost is a great reference and library that I use all the time.
Oh, and please note that though you can do partial specialization for functions as well, it may not work as expected. It is far more easier to understand when used with classes.
Hope this helps.
A
-
October 18th, 2011, 04:29 AM
#10
Re: problem for defining template class
Originally Posted by adrian_h
Oh, and please note that though you can do partial specialization for functions as well, it may not work as expected. It is far more easier to understand when used with classes.
Nice post, however, I thought that I would point out that the partial template specialisation of a function is not allowed in C++. You can template functions, and fully specialise template functions, but you cannot partially specialise them. Instead, the C++ standard allows template functions to be overloaded in the same way as non-template functions. This means that whilst you cannot partially specialise them i.e.
Code:
#include <iostream>
template <typename T, typename U>
void function_test(T t, U u)
{
std::cout << t << " " << u << std::endl;
}
template <typename T>
void function_test<T, int>(T t, int u) //Red part not allowed
{
std::cout << t << " " << u << std::endl;
}
int main()
{
function_test("hello", 52);
}
You can write an overload
Code:
#include <iostream>
template <typename T, typename U>
void function_test(T t, U u)
{
std::cout << t << " " << u << std::endl;
}
template <typename T>
void function_test(T t, int u) //Red part removed - now allowed
{
std::cout << t << " " << u << std::endl;
}
int main()
{
function_test("hello", 52);
}
I hope this helps.
-
October 18th, 2011, 10:59 AM
#11
Re: problem for defining template class
Originally Posted by PredicateNormative
Nice post, however, I thought that I would point out that the partial template specialisation of a function is not allowed in C++. You can template functions, and fully specialise template functions, but you cannot partially specialise them. Instead, the C++ standard allows template functions to be overloaded in the same way as non-template functions. This means that whilst you cannot partially specialise them i.e.
...
Yeah, that's what I meant. Nice catch PN.
A
-
October 21st, 2011, 05:27 AM
#12
Re: problem for defining template class
Sorry for the late response. Thank you all. All your suggestions are valueable for me. Based on your suggestions, I figured out the solution like the following:
Code:
struct value_tag {};
struct pointer_tag {};
template<typename T>
struct function_traits
{
typedef value_tag function_categrory;
};
template<typename T>
struct function_traits<T*>
{
typedef pointer_tag function_categrory;
};
template <typename T1>
class A
{
public:
A() {}
~A() {}
void doFunction( T& arg, value_tag )
{
arg.itsMemberFunc();
}
void doFunction( T* arg, pointer_tag )
{
arg->itsMemberFunc();
}
void memFunction( T arg )
{
doFunction( arg, function_traits<T>::function_categrory() );
}
};
So in a main file, it works like this:
Code:
class AnotherClass
{
public:
void itsMemberFunc()
{
}
};
int main()
{
A<AnotherClass> aDouble;
AnotherClass var1;
aDouble.memFunction( var1 );
A<AnotherClass*> anotherClass;
AnotherClass* var2 = new AnotherClass;
anotherClass.memFunction( var2 );
return 0;
}
This method maybe not a better one. But it works for my case. Thank you very much again. This is a really good lesson for me.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|