I'm new in using templates in C++, I want to do different things depending on type used between < and >, so function<int>() and function<char>() won't do the same things.
How can I achieve this?
template<typename T> T* function()
{
if(/*T is int*/)
{
//...
}
if(/*T is char*/)
{
//...
}
return 0;
}
You want to use explicit specialization of your function template:
template<class T> T* function() {
};
template<> int* function<int>() {
// your int* function code here
};
template<> char* function<char>() {
// your char* function code here
};
Create template specializations:
template<typename T> T* function()
{
//general case general code
}
template<> int* function<int>()
{
//specialization for int case.
}
template<> char* function<char>()
{
//specialization for char case.
}
Best practices involves tag dispatch, because specialization is tricky.
Tag dispatch is easier to use quite often:
template<typename T>
T* only_if_int( std::true_type is_int )
{
// code for T is int.
// pass other variables that need to be changed/read above
}
T* only_if_int( std::false_type ) {return nullptr;}
template<typename T>
T* only_if_char( std::true_type is_char )
{
// code for T is char.
// pass other variables that need to be changed/read above
}
T* only_if_char( std::false_type ) {return nullptr;}
template<typename T> T* function()
{
T* retval = only_if_int( std::is_same<T, int>() );
if (retval) return retval;
retval = only_if_char( std::is_same<T, char>() );
return retval;
}
template<class T>
T Add(T n1, T n2)
{
T result;
result = n1 + n2;
return result;
}
For In detail understanding of template, go through the below link:
http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part-1
you can define overloaded functions something like this:
#define INTT 0
#define CHARR 1
template<typename T>
T* function()
{
int type;
type = findtype(T);
//do remaining things based on the return type
}
int findType(int a)
{
return INTT;
}
int findType(char a)
{
return CHARR;
}
Related
Suppose I have a method which is simplified to this
template<typename t,typename u>
std::shared_ptr<bar> MyClass::getFunct(std::string SomeStr)
{
.....
std::map<std::string,std::shared_ptr<foo> > j;
....
std::shared_ptr<u> collection(new u());
for (auto val : j){
val.second->getMethodA() //Will return object of type t <----LINE A
}
}
Now I am using it as
getFunct<FirstType>("SomeString")
getFunct<SecondType>("SomeString")
getFunct<ThirdType>("SomeString")
Now val.second in Line A
has 3 methods in it
val.second->getMethodA() //returns a type of FirstType
val.second->getMethodB() //returns a type of SecondType
val.second->getMethodC() //returns a type of ThirdType
Currently i am using
val.second->getMethodA() with template type FirstType
is there anyway for me to specify to use getMethodB if template type is SecondType
and use getMethodC if template type is ThirdType
The simplest solution is to replace the three getMethodX member functions with a single template function template<class T> T foo::getMethod(). Then create specializations for each type, if needed.
But if that is not appropriate for the design, then you can use a wrapper function instead:
template<class T>
struct helper {};
template<>
struct helper<FirstType> {
static FirstType getMethod(foo& f) {
return f.getMethodA();
}
};
// repeat specializations for other member functions
With C++17 you can use constexpr if:
template<typename T>
decltype(auto) foo(Bar& bar){
if constexpr(std::is_same_v<T,FirstType>){
return bar.getMethodA();
}
if constexpr(std::is_same_v<T,SecondType>){
return bar.getMethodB();
}
if constexpr(std::is_same_v<T,ThirdType>){
return bar.getMethodC();
}
}
In the absence of C++17 I would probably go for something simple like this:
template <typename T> struct type {};
struct select
{
bar &b;
decltype(auto) operator()(type<FirstType>) const { return b.getMethodA(); }
decltype(auto) operator()(type<SecondType>) const { return b.getMethodB(); }
decltype(auto) operator()(type<ThirdType>) const { return b.getMethodC(); }
};
select{*val.second}(type<T>{});
In the context of your example:
template <typename T> struct type {};
template<typename t,typename u>
std::shared_ptr<bar> MyClass::getFunct(std::string SomeStr)
{
.....
std::map<std::string,std::shared_ptr<foo> > j;
....
for (auto val : j) {
struct select {
bar &b;
decltype(auto) operator()(type<FirstType>) const { return b.getMethodA(); }
decltype(auto) operator()(type<SecondType>) const { return b.getMethodB(); }
decltype(auto) operator()(type<ThirdType>) const { return b.getMethodC(); }
};
select{*val.second}(type<t>{});
}
}
Given the following declaration:
template<class T>
class A {
void run(T val) {
val.member ...
}
}
This code works fine if no pointers are used:
A<Type> a;
Type t;
a.run(t);
But using a pointer results in an error:
A<Type*> a;
Type* t = new Type();
a.run(t);
error: request for member ‘member’ which is of non-class type ‘T*’
Obviously in this case the member must be accessed via ->. What's the best way to handle this?
I found a solution on SO: Determine if Type is a pointer in a template function
template<typename T>
struct is_pointer { static const bool value = false; };
template<typename T>
struct is_pointer<T*> { static const bool value = true; };
...
if (is_pointer<T>::value) val->member
else val.member
But this is very verbose. Any better ideas?
You could use a simple pair of overloaded function templates:
template<typename T>
T& access(T& t) { return t; }
template<typename T>
T& access(T* t) { return *t; }
And then use them this way:
access(val).member = 42;
For instance:
template<typename T>
struct A
{
void do_it(T& val)
{
access(val).member = 42;
}
};
struct Type
{
int member = 0;
};
#include <iostream>
int main()
{
A<Type> a;
Type t;
a.do_it(t);
std::cout << t.member << std::endl;
A<Type*> a2;
Type* t2 = new Type(); // OK, I don't like this, but just to show
// it does what you want it to do...
a2.do_it(t2);
std::cout << t2->member;
delete t2; // ...but then, don't forget to clean up!
}
Here is a live example.
The best idea is probably to specialize your class for pointer types.
template<class T>
class A{ ...};
template<>
class A<T*> { //implement for pointers
};
If you feel that this is too verbose, you can use overload a get_ref function:
template<class T> T& get_ref(T & r) {return r;}
template<class T> T& get_ref(T* r) {return *r;}
template<class T>
class A {
void do(T val) {
get_ref(val).member ...
}
}
I am writing a sort of serialization class. It must provide functions for containers. Current implementation is:
template <typename InsertIter>
bool readContainer(InsertIter result)
{
typedef typename InsertIter::container_type::value_type tVal;
UInt32 size = 0;
if (!read(size))
return false;
for (UInt32 i = 0; i < size; ++i)
{
tVal val;
if (!read(val))
return false;
*result++ = val;
}
return true;
}
template <typename InsertIter>
bool readMap(InsertIter result)
{
typedef typename InsertIter::container_type::key_type tKey;
typedef typename InsertIter::container_type::mapped_type tVal;
UInt32 size = 0;
if (!read(size))
return false;
for (UInt32 i = 0; i < size; ++i)
{
std::pair<tKey, tVal> pair;
if (!read(pair))
return false;
*result++ = pair;
}
return true;
}
As you can see, I must to create different implementations for map-like types (std::map) and other containers, because std::map::value_type is std::pair(const K, V) and not std::pair(K, V).
So, I want to create method read(InsertIter) which will automatically select appropriate readContainer(InsertIter) or readMap(InsertIter). Is this possible?
I have an example that does something very similar, and it should be very simple for you to convert to something that you need :
#include <iostream>
template< typename T >
struct A;
template<>
struct A< int >
{
void foo() const
{
std::cout<<"A(int)::foo()"<<std::endl;
}
};
template<>
struct A< float >
{
void foo() const
{
std::cout<<"A(float)::foo()"<<std::endl;
}
};
template< typename T >
void call( const A<T> &a)
{
a.foo();
}
struct B
{
template<typename T>
void bar(const A<T> &a)
{
call(a);
}
};
int main()
{
A<int> a1;
A<float> a2;
B b;
b.bar(a1);
b.bar(a2);
}
You need to give proper names, and replace int and float in the above example with appropriate container types, and implement needed functionality.
I have successfully solved my problem.
Thanks to Johan Lundberg and especially to n.m. - I was not familiar with SFINAE idiom and your links and samples helped me a lot.
I was not able to use C++11 features (project specifics), but they are not needed.
Current code looks like this:
struct SFINAE
{
typedef char __one;
typedef struct { char __arr[2]; } __two;
};
template <typename T>
class has_mapped_type : public SFINAE
{
template <typename C> static __one test(typename C::mapped_type *);
template <typename C> static __two test(...);
public:
enum { value = (sizeof(test<T>(0)) == sizeof(__one)) };
};
class Serializer
{
template <typename InsertIter>
bool read(InsertIter result) const
{
return readContainerSelector< InsertIter,
has_mapped_type<typename InsertIter::container_type>::value
> ::read(result, *this);
}
template <typename InsertIter, bool isMapType>
struct readContainerSelector;
template <typename InsertIter>
struct readContainerSelector<InsertIter, true>
{
static bool read(InsertIter result, Serializer const& ser)
{
return ser.readMap(result);
}
};
template <typename InsertIter>
struct readContainerSelector<InsertIter, false>
{
static bool read(InsertIter result, Serializer const& ser)
{
return ser.readContainer(result);
}
};
// methods from my topic post
template <typename InsertIter> bool readContainer(InsertIter result);
template <typename InsertIter> bool readMap(InsertIter result)
};
I would like to achieve something like that:
template<class... Args>
class MyClass{
public:
MyClass(){
for(auto arg : {sizeof(Args)...})
std::cout<<arg<<std::endl;
}
};
But with one simple exception. The type char* should return 0(or everything else, what will be distinct from an int).
How about the following?
/* heavily borrowed from IBM's variadic template page */
#include <iostream>
using namespace std;
/*
template<typename T> struct type_size{
operator int(){return sizeof( T );}
};
template<> struct type_size <char *>{
operator int(){return 0;}
};
*/
/* as per Mattieu M.'s suggestion */
template<typename T> constexpr size_t type_size(T dummy) {
return sizeof dummy;
}
constexpr size_t type_size(char *){
return 0;
}
template <typename...I> struct container{
container(){
int array[sizeof...(I)]={type_size<I>()...};
printf("container<");
for(int count = 0; count<sizeof...(I); count++){
if(count>0){
printf(",");
}
printf("%d", array[count]);
}
printf(">\n");
}
};
int main(void){
container<int, short, char *> g;
}
template<typename T>
std::size_t size()
{
return sizeof(T);
}
template<>
std::size_t size<char*>()
{
return 0;
}
template<class... Args>
class MyClass{
public:
MyClass()
{
std::initializer_list<char> { (std::cout << size<Args>(), void(), char {})... };
}
};
Although in truth I have an EXPAND macro that hides the std::initializer_list ugliness (not to mention void() + comma operator trick) such that it would look like EXPAND( std::cout << size<Args>() ).
I would like to provide a templated function, that varies its implementation (->specialization) according to the sizeof the template type.
Something similar to this (omitted typecasts), but without the if/elseif:
template<class T>
T byteswap(T & swapIt)
{
if(sizeof(T) == 2)
{
return _byteswap_ushort (swapIt);
}
else if(sizeof(T) == 4)
{
return _byteswap_ulong(swapIt);
}
else if(sizeof(T) == 8)
{
return _byteswap_uint64(swapIt);
}
throw std::exception();
}
I know there are many roads to reach my goal, but since I try to learn about SFINAE and type traits I'm particularly interested in solutions using those techniques to decide at compile time which specialization to choose and which calls are not admitted.
Perhaps implementing a class trait is_4ByteLong and using boost::enable_if...
I have to admit, I'm stuck right now, so I thank you for any help or advice
You don't need SFINAE or type traits. Vanilla template specialization is enough. Of course it must be specialized on structs as C++(98) doesn't support function template partial specialization.
template <typename T, size_t n>
struct ByteswapImpl
/*
{
T operator()(T& swapIt) const { throw std::exception(); }
}
*/ // remove the comments if you need run-time error instead of compile-time error.
;
template <typename T>
struct ByteswapImpl<T, 2> {
T operator()(T& swapIt) const { return _byteswap_ushort (swapIt); }
};
// ...
template <typename T>
T byteswap(T& swapIt) { return ByteswapImpl<T, sizeof(T)>()(swapIt); }
Simply make an auxiliary class that takes the size as a template argument:
#include <cstddef>
#include <iostream>
template<std::size_t Size>
struct ByteSwapper { };
template<>
struct ByteSwapper<2> {
static unsigned short swap(unsigned short a) {
return 2 * a;
}
};
template<typename T>
T byteswap(const T& a) {
return ByteSwapper<sizeof(T)>::swap(a);
}
int main() {
unsigned short s = 5;
std::cout << byteswap(s) << std::endl;
unsigned int i = 7;
// std::cout << byteswap(i) << std::endl; // error
}
Just for the sake of demonstrating enable_if in action, since you spoke about it:
template <class T>
typename boost::enable_if_c< sizeof(T) == 2, T >::type
swapIt(T& rhs) { return _byteswap_short(rhs); }
template <class T>
typename boost::enable_if_c< sizeof(T) == 4, T >::type
swapIt(T& rhs) { return _byteswap_long(rhs); }
etc...
And of course, instead of throwing, there is just no implementation if the type doesn't meet any of the requirement and thus you have a compile time error.
Two notes:
Use of typename and ::type are mandatory
I used enable_if_c because my expression evaluates to a boolean value directly, whereas enable_if requires a type containing a ::value member which is a boolean.
I can propose the following method:
Its benefit is that you don't have to throw an exception if the operand isn't of the valid size. It just won't link. So that you have the error checking at build time.
template<int size>
void byteswapInPlace(void* p);
template<> void byteswapInPlace<1>(void* p) { /* do nothing */ }
template<> void byteswapInPlace<2>(void* p)
{
_byteswap_ushort((ushort*) p);
}
template<> void byteswapInPlace<4>(void* p)
{
_byteswap_ulong((ulong*) p);
}
template<> void byteswapInPlace<8>(void* p)
{
_byteswap_uint64((uint64*) p);
}
template<class T>
T byteswap(T & swapIt)
{
byteswapInPlace<sizeof(T)>(&swapIt);
return swapIt;
}