I have a BinaryMemoryReader class that has a function defined like this:
template <typename T>
inline void read(T **data) {
*data = (T*)&stream[position];
position += sizeof(T);
}
It handles most of the standard types from a stream in memory.
The custom complex types have read functions of their own, such as:
void AnotherClass::read(BinaryMemoryReader *const reader)
{
reader->read<bool>(&num);
reader->read<short>(&count);
}
What I'd like to is write the code that would, when I write
reader->read<AnotherClass>(&var);
would call the second function. It would mean that AnotherClasss read function would overload the BinaryMemoryReaders read function for that particular type.
It would allow me to write a much more cleaner code.
EDIT:
The general idea is this:
Have a central BinaryMemoryReader class.
Have a generic read function within it to deal with the standard types.
Have the syntax to call it be bmr->read<int>(&intVar);
Have specialized read functions defined in their own classes.
Most importantly, the syntax to call them would be bmr->read<customType>(&customTypeVar);
That way the specific read functions would be associated with their own classes, but would be able to be called from the BinaryMemoryReader.
As I wrote in my comment I would use the following approach:
Have a templated free function
template <typename T>
void read(BinaryMemoryReader& bmr, T& data) {
bmr.read(&data);
}
Specialize that function for each of the types you want to handle
class AnotherClass {
template <typename T>
friend void read(BinaryMemoryReader& bmr, T &data);
bool num;
short count;
};
template <>
void read(BinaryMemoryReader& bmr, AnotherClass &data) {
bmr.read<bool>(&(data.datanum));
bmr.read<short>(&(data.count));
};
Call it like
BinaryMemoryReader bmr;
AnotherType at;
read(bmr,at);
That technique is used for instance with the c++ standard I/O library and overloads provided for the
std::ostream& operator<<(std::ostream&, const T&);
std::istream& operator>>(std::istream&, T&);
functions.
Alternatively you could do that specialization for the BinaryMemoryReader::read() function. But BinaryMemoryReader must be friend of all class specializations.
Related
I'm currently writing a template class for archiving (or serializing) and unarchiving data into/from a binary format. First off, I'm trying to close on what pattern I'll use. I am mostly inclined to using templates because unarchivers don't have an input type for method overloading. For instance, the following example is OK:
Archiver ar;
int i;
archive(ar, i);
But it's counterpart isn't:
Unarchiver unar;
int i;
i = unarchive(unar);
I would like to avoid using the function's name, such as unarchive_int because it would be troublesome when using templates. Say:
template <class T> class SomeClass
{
public:
void doSomething()
{
// Somewhere
T value = unarchive(unar);
}
};
This would make things messy, and as such I rather really use templates for this, whereas the previous expression would be T value = unarchive<T>(ar);. It also seems silly (arguably) to write a global function if either the first or only parameter are always the archiver and unarchiver objects; a template class seems to be in order:
template <class T> class Archiver
{
public:
void archive(T obj);
};
This works, but the archiving method always copies its input object. This is OK with POD data types, but not so much which classes. The solution seems obvious, and instead use a const reference as in void archive(const T & obj), but now it also seems silly to be passing integers, floats, and other PODs by reference. Although I would be happy with this solution, I tried to go a little further and have the object make the distinction instead. My first approach is std::enable_if, while assuming a copy by default (for all non-class members) and provide a class specialization where the archive method gets its input by reference instead. It doesn't work. Here's the code:
template <class T, class E = void>
class Archiver
{
public:
// By default, obj is passed by copy
void archive(T obj);
};
template <class T>
class Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::value>
{
public:
// I would expect this to be used instead if is_class<T> && !is_pod<T>
void archive(const T & obj);
};
The problem is that the second declaration is not visible at all to the compiler, and here's proof:
template <> void Archiver<std::uint8_t>::archive(uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
The former compiles fine, but the later gives:
out-of-line declaration of 'archive' does not match any declaration in
'Archiver<std::__1::basic_string<char>, void>'
On the other hand, if I get the std::string instead by copy if compiles just fine. I think I know why this happens, the compiler chooses the first template as it's generic enough for both declarations, but then how do I make it choose the more specialized version?
You want std::enable_if<...>::type, not std::enable_if<...>::value.
Here's a full demo:
#include <type_traits>
#include <cstdint>
#include <string>
template <class T, class E = void>
struct Archiver {
void archive(T obj);
};
template <class T>
struct Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::type>
{
void archive(const T & obj);
};
template <> void Archiver<std::uint8_t>::archive(std::uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
IIUC, the question boils down to how to define a generic template type that is optimized for calling functions.
For this, you can consider boost::call_traits, in particular, param_type:
template<typename T>
void foo(typename boost::call_traits<T>::param_type t);
I am writing a comparator for strings. However I want it to work for both strings and char*s.
Something like StringComparer<std::string, std::string> and StringComparer<const char *, const char*>. Of course, inside the implementation for Stringcomparer<const char *, const char *> I will simply do a std::string Stringversion(<pass the const char* here>) for both strings and simply call the Stringcomparer<std::string, std::string>.
How can I write two such templated functions for my Stringcomparer.
I have been looking for this and all I can find everywhere are examples where people have defined a function like this:
template <typename T> foo(T&)
{
//some operation on T that does depends on operators or functions that can handle any //type like sort or cout. basically there are showing that this fucntion can be used to sort //both integer and string vectors or it can cout both integers and floats.
}
Can you please tell me how I can provide multiple variants of my stringcomparer. Surely there are times when people need to write a separate routine handling each type. How is this accomplished.
You can declare a primary function template and the [fully] specialize it for different types, e.g.:
template <typename T> void foo(T&); // primary template declaration
template <> void foo<std::string>(std::string& s) { // specialization for std::string
// ...
}
template <> void foo<char*>(char *&s) { // specialization for char*
// ...
}
Note that the specializations have to match the primary template with the specialized type replaced exactly! In general, I find it easier to specialize class template implementing function objects (i.e., have a function call operator) and delegate to these from a general function template.
You can use template specialisations. Here is a short example.
template <typename T>
void foo(const T& arg)
{
// code
}
// Specialises the function template for char*
template <>
void foo(const char*& arg)
{
// different code
}
EDIT: Oops, specialised for string to start with.
mem_fun and mem_fun_ref and many other member function adaptors can make member functions act like orindinary functions. But there is one restriction that the member function that they call must be a const one. I get to know how to use them, but confused and puzzled by the reasons behind it. Why is it designed in this way?
update:
Sorry for the ambiguity. write an example below.
class A
{
...
//void fun(){cout<<"Fun";} This is not const and the compiler would complain
void fun() const {cout<<"Not fun";}
...
}
vector<A> avec;
...
for_each(avec.begin(),avec.end(),mem_fun_ref(&A::fun));
...
There is no such a restriction. These template functions are overloaded for const and non-const member functions.
For example
template<class S, class T>
mem_fun_t<S,T> mem_fun(S (T::*f)());
template <class S, class T>
const_mem_fun_t<S,T> mem_fun(S (T::*f)() const);
I am aware that the syntax for declaring a template class method in a header and defining it in a source file goes as so:
myclass.h
template <typename T>
class MyClass {
public:
void method(T input);
private:
T privVar;
};
myclass.cpp
template <typename T>
void MyClass<T>::method(T input) {
privVar = input;
}
But, what if the method is also a template?
I am adding methods to the basic_string class, and I want to know how to write the implementation for the functions.
MyString.h
template <class _Elem = TCHAR,
class _Traits = std::char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
class String
: public std::basic_string<_Elem, _Traits, _Ax> {
private:
// Types for the conversion operators.
typedef _Elem* _StrTy;
typedef const _Elem* _ConstStrTy;
//...
public:
// Conversion operators so 'String' can easily be
// assigned to a C-String without calling 'c_str()'.
operator _StrTy() const {
return const_cast<_StrTy>(this->c_str());
}
operator _ConstStrTy() const {
return this->c_str();
}
// ... Constructors ...
/*------------ Additional Methods ------------*/
//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val);
//! Converts a string to the given type.
template <class _ValTy> static _ValTy ConvertTo(const String& str);
template <class _ValTy> _ValTy ConvertTo(void) const;
//! Checks if a string is empty or is whitespace.
static bool IsNullOrSpace(const String& str);
bool IsNullOrSpace(void) const;
//! Converts a string to all upper-case.
static String ToUpper(String str);
void ToUpper(void);
// ...
};
How could I implement template <class _ValTy> static String ConvertFrom(_ValTy val);? Because now not only do I need to specify the class template, but the function template too. I am betting the code I'm about to write isn't valid, but it should show what I am trying to accomplish:
MyString.cpp
template <class _Elem, class _Traits, class _Ax>
template <class _ValTy>
String<_Elem, _Traits, _Ax> String<_Elem, _Traits, _Ax>::ConvertFrom(_ValTy val) {
// Convert value to String and return it...
}
I am not advanced at all with templates. Not only am I very doubtful that the above is valid, it seems cumbersome to write and not very readable. How would I go about implementing the template methods, and the static template methods which returns its own class type? Because I don't want to define them in the header.
Syntax of definition of template member functions outside of template is like this:
template <class T> struct A
{
template <class X> void f();
};
template<class T> template<class X> void A<T>::f()
{
}
So your code is correct.
Would like to note that defining template members in .cpp is not very useful. In this case you shall explicitly instantiate them with all types you need to use with this template. Or do not use them outside this .cpp which doesn't make sense.
Before I answer your question, let me first say: Don't do this. Extend std::string by using free-functions instead, much like the standard library implements many algorithms. Additionally I'd suggest doing it for ranges rather than strings only but that's more subjective.
Also note that std::string avoids implicit conversions to C-strings not to make your life harder, but to protect your code from a wide variety of obscure bugs that can be caused by unexpected implicit conversions. I would think very long and hard about implementing them. Just think about this: It takes you a few extra moments to type.c_str() once when you write the code, and for the rest of eternity anyone who reads your code will immediately know that it's being used as a C-style string and not as a std::string.
To answer your question, just put the code in the header:
//! Converts a value of the given type to a string.
template <class _ValTy> static String ConvertFrom(_ValTy val)
{
// Code here
}
Finally note that identifiers starting with underscore+capital letter (and many other things starting with _) are reserved for the compiler and thus all bets are off as to your program's functionality.
Your function definition is valid, and it can't be defined outside of the class declaration in a less verbose way. Since you want to put the function definition in a .cpp file you can't take advantage of combining the function definition with the more concise function declaration. By putting the function definition in a .cpp file you will also have to explicitly instantiate all needed specializations of your template class.
Below is an attempt to make an example code for Rost and Josh's answers:
template.hpp
#pragma once
template<class T>
class Add
{
public:
T Addition(T summand1, T summand2);
};
void AddUsing( int summand1, int summand2 );
template.cpp
#include "template.hpp"
#include <iostream>
template<class T>
T Add<T>::Addition(T summand1, T summand2)
{
return summand1 + summand2;
}
void AddUsing( int summand1, int summand2 )
{
std::cout << Add<int>().Addition( summand1, summand2 ) << std::endl;
}
main.cpp
#include "template.hpp"
int main()
{
AddUsing ( 2, 2 );
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to write a C++ template to check for a function's existence?
I am trying to write a C++ class template. What I want is when this class template is used with user defined classes, I want to force those user defined classes to implemented certain methods say e.g., to_data and from_data. I do not want those for basic C++ primitive datatypes. How do I do this? For example, std::vector give compilation error if the copy constructor of the class is not available.
You can make the methods that must be implemented by user pure virtual functions. If you don't want those for basic C++ primitive datatypes, you can specialize your template for these situations and provide default implementations for these cases.
Simply use the methods in your class template:
template <typename T>
struct Serializer
{
void serialize(T const & t) const { write(t.to_data()); }
void deserialize(T & t) const { t.from_data(read()); }
};
If the types you instantiate the template with have the appropriate member functions, everything will be fine. If they don't, the compiler will trigger an error:
struct Foo
{
int val;
int to_data() const { return val; }
void from_data(int i) { val = i; }
};
struct Bar {};
Serializer<Foo> sf;
sf.serialize(); // OK
Serializer<Bar> sb;
sb.serialize(); // compiler error: Bar has no member function named "to_data"
Note that the compiler error is only triggered when we try to use some functions of the class template. This is because member functions of class templates are only instantiated (compiled, if you will) when you use them. So it is perfectly fine to instantiate Serializer with Bar as long as you don't use the serialize and deserialize member function.
Regarding the second issue, namely how to provide a different behavior for primitive types, you have several solutions. The first one is to specialize your class template for the types you want to handle differently. For instance, the following code specializes Serializer so that it handles int differently:
template <>
struct Serializer<int>
{
void serialize(int i) const { write(i); }
void deserialize(int & i) const { i = read();
};
However, this implies writing a specialization for each particular type, even if some of them are in fact handled in the same way.
A less cumbersome solution would be to use type traits and std::enable_if to select the correct implementation depending on some characteristics of the arguments types (in this case, whether they are primitive or not):
#include <type_traits>
template <typename T, typename Enable = void>
struct Serializer
{
// same as before
};
// Partial specialization for fundamental types
template <typename T>
struct Serializer<T, typename
std::enable_if<std::is_fundamental<T>::value>::type>
{
void serialize(T t) const { write(t); }
void deserialize(T & t) const { t = read(); }
};
Serializer<Foo> sf; // first implementation
Serializer<int> si; // second (specialized) implementation