I am pretty new with templates
I have below code that I try to hide my template class behind a base interface class.
It works now but I dont know if its a good way to do what I try to do.
For example is it possible to collect insertItem() functions in one common function also?
struct MyMainClass
{
virtual void writeFirstItem() = 0;
virtual void insertItem(int Key, int Value) = 0;
virtual void insertItem(void* Key, int Value) = 0;
};
template<typename T>
struct MyTempClass : public MyMainClass
{
template<typename T>
struct cmp_str
{
bool operator()(typename T const a, typename T const b) const
{
if(a > b)
return true;
return false;
};
};
template<>
struct cmp_str<wchar_t*>
{
bool operator()(wchar_t* const a, wchar_t* const b) const
{
return std::wcscmp(a, b) < 0;
};
};
template<>
struct cmp_str<char*>
{
bool operator()(char* const a, char* const b) const
{
return std::strcmp(a, b) < 0;
};
};
typedef std::map<typename T, int, cmp_str<typename T> > Mymap;
typedef typename Mymap::const_iterator mymapit;
typename Mymap mymap;
template<typename T>
void insert(T keyVal, int myvalue)
{
mymap[keyVal] = myvalue;
};
void writeFirstItem()
{
std::wcout << std::wstring(L"(") << mymap.begin()->first << L"," << mymap.begin()->second << L")" << std::endl;
}
void insertItem(void* Key, int Value)
{
insert((T)Key, Value);
}
//this one shouldnt be called
void insertItem(int Key, int Value){}
};
template<> template<>
void MyTempClass<int>::insert<int>(int keyVal, int myvalue)
{
mymap[keyVal] = myvalue;
}
template<>
void MyTempClass<int>::insertItem(int Key, int Value)
{
insert(Key, Value);
}
int wmain(int argc, wchar_t* argv[])
{
MyMainClass* a;
MyMainClass* b;
MyMainClass* c;
wchar_t a1[6] = L"asdf";
wchar_t a2[6] = L"12345";
wchar_t a3[6] = L"xyzs";
wchar_t a4[6] = L"12345";
int b1 = 3;
int b2 = 5;
int b3 = 88;
int b4 = 3;
char c1[6] = "casdf";
char c2[6] = "c1234";
char c3[6] = "cxyzs";
char c4[6] = "c1234";
a = new MyTempClass<wchar_t*>;
a->insertItem(a1,3);
a->insertItem(a2,5);
a->insertItem(a3,9);
a->insertItem(a4,3);
b = new MyTempClass<int>;
b->insertItem(b1, 4);
c = new MyTempClass<char*>;
c->insertItem(c1,77);
c->insertItem(c3,99);
a->writeFirstItem();
b->writeFirstItem();
c->writeFirstItem();
}
What you've got is type redefinition, I guess. This is because when you're compiling without "else" section, only one cmp_str specialization is actually "instantiated", when you uncomment "else" - another "struct cmp_str" appears in the same translation unit.
Please tell us what you're trying to achieve with this combination.
The problem is that your first argument to insert() is of incorrect type.
When you instantiate MyTempClass<int>, the insert() function's signature becomes:
void insert(int keyVal, int myvalue); however your call-site for insert looks like, b->insert(a1, 3); where a1 is not of type int.
Related
I wrote some kind of index and I am trying to use it.
When I run the program in debug mode everything seems to be fine, but in release mode the program exits with code -1073741819 (hex: FFFFFFFFC0000005); this seems to be an access violation.
The code uses data type unsigned __int128. When I replace this by uint64_t the program works also in release mode.
I am not sure, but using templates could also play a role. And even commenting out a function call (FindAllByFirstID in SomeFunc) that is never reached leads to seemingly correct execution in release mode.
I am not experienced in C++. Perhaps I overlook something. But my guess is that there is something overridden by the big datatype __int128. Maybe something can't deal with that type?
Can someone please help?
Unfortunately I was not able to even more shorten the code. (I know, in this form it makes little sense, but nevertheless it should execute correctly.)
#include <map>
#include <string>
#include <vector>
using namespace std;
#define ID_t unsigned __int128
struct __attribute__ ((packed)) DATA_t {
ID_t tid;
union {
array<uint16_t, 0> a;
uint8_t aDummy[4];
} data;
array<ID_t, 2> id;
};
template<class I>
class Entry {
public:
I data;
Entry<I>() {};
Entry<I>(const Entry<I>& orig) {};
virtual ~Entry<I>() {};
private:
};
template<class I>
struct ID_cmp {
bool operator()(const I& a, const I& b) const {
return a.id < b.id;
}
};
template<class I>
struct DATA_cmp {
bool operator()(const I& a, const I& b) const {
return a.data.a < b.data.a;
}
};
template<class I> class Index;
template<class I>
class IndexData {
public:
IndexData(Index<I>* index) : index(index) {};
IndexData(const IndexData<I>& orig) {};
virtual ~IndexData() {};
bool InsertOrFindEntry(Entry<I>** entry) {
if (!entries) {
entries = new map<I, Entry<I>*, DATA_cmp < I >> ();
Entry<I> modEntry;
modEntry.data = (*entry)->data;
index->CreateEntry(&modEntry.data);
}
auto search = entries->find((*entry)->data);
if (search == entries->end()) {
entries->operator[]((*entry)->data) = *entry;
return true;
} else {
delete *entry;
*entry = search->second;
return false;
}
};
Entry<I>* FindEntry(const I* data) {
if (entries) {
auto entry = entries->find(*data);
return entry == entries->end() ? nullptr : entry->second;
}
return nullptr;
};
void PushAllEntries(vector<Entry<I>*>& datas) {
if (entries) for (const auto& e : *entries) datas.push_back(e.second);
};
private:
Index<I>* index;
map<I, Entry<I>*, DATA_cmp<I>>* entries = nullptr;
};
template<class I>
class IndexID {
public:
IndexID(Index<I>* index) {
this->index = new IndexData<I>(index);
};
IndexID(const IndexID<I>& orig) {};
virtual ~IndexID() {};
bool InsertOrFindEntry(Entry<I>** entry) {
return index->InsertOrFindEntry(entry);
};
Entry<I>* FindEntry(const I* data) {
return index->FindEntry(data);
};
void PushAllEntries(vector<Entry<I>*>& datas) {
if (index) index->PushAllEntries(datas);
};
private:
IndexData<I>* index = nullptr;
};
class IndexCommon {
public:
IndexCommon() {};
IndexCommon(const IndexCommon& orig) {};
virtual ~IndexCommon() {};
virtual void SomeFunc(void* entry) {};
private:
};
template<class I>
class Index : public IndexCommon {
public:
Index() {};
Index(const Index<I>& orig) {};
virtual ~Index() {};
bool InsertOrGetEntry(Entry<I>** entry) {
IndexID<I>* indexID = GetIndexID(&(*entry)->data);
return indexID->InsertOrFindEntry(entry);
};
Entry<I>* CreateEntry(const void* data) {
Entry<I>* entry = new Entry<I>();
entry->data = *(I*) data;
if (InsertOrGetEntry(&entry)) SomeFuncCreate(entry);
return entry;
};
void FindAllByFirstID(const ID_t id, vector<Entry<I>*>& datas);
void SomeFuncCreate(Entry<I>* entry);
void SomeFunc(void* entry) override;
private:
map<I, IndexID<I>*, ID_cmp<I>> indexID;
IndexID<I>* GetIndexID(const I* data) {
auto search = indexID.find(*data);
if (search == indexID.end()) {
IndexID<I>* idxID = new IndexID<I>(this);
indexID[*data] = idxID;
return idxID;
}
return search->second;
};
};
template <class I>
inline void Index<I>::FindAllByFirstID(const ID_t uid, vector<Entry<I>*>& datas) {
DATA_t search;
search.id[0] = uid;
search.id[1] = 0;
auto lower = indexID.lower_bound(search);
search.id[1] = UINT64_MAX;
auto upper = indexID.upper_bound(search);
if (lower == indexID.end()) return;
for (auto it = lower; it != upper; ++it) (*it).second->PushAllEntries(datas);
}
template<class I>
inline void Index<I>::SomeFuncCreate(Entry<I>* entry) {
vector<Entry<I>*> datas;
FindAllByFirstID(entry->data.id[1], datas);
}
template<class I>
inline void Index<I>::SomeFunc(void* entry) {
vector<Entry<I>*> datas;
FindAllByFirstID(((Entry<I>*)entry)->data.id[1], datas);
}
int main(int argc, char** argv) {
Index<DATA_t> myIndex = Index<DATA_t>();
Entry<DATA_t>* myEntry = new Entry<DATA_t>();
myIndex.InsertOrGetEntry(&myEntry);
return 0;
}
I work with Netbeans 11.1 on Win10, with MSYS_NT-10.0-19041.
I tried to shorten the code as far as possible, commented out every function and so on. I hoped, I could encircle the problem but it didn't really work it. If I remove to much of the code it works. All in all the behaviour seems to me to be not comprehensible.
I am using a base class and a child class defined above main in main.cpp
this gives me an error of undefined reference FactoryTraversal::AddPoint::AddPoint(int const&, int const&, int)'
Here is the code:
#include <iostream>
#include <list>
#include <typeinfo>
#include <cmath>
enum traversal_type
{
TRAVERSAL = 0,
TRAVERSALMAX
};
template <class T>
class FactoryTraversal
{
public:
FactoryTraversal();
FactoryTraversal *CreateInstance(const traversal_type &type);
virtual ~FactoryTraversal();
const std::list<int>& GetIndices() const {return indices;}
int GetIndicesSize() const {return indices.size();}
virtual void AddPoint(const T &x, const T &y, int index);
protected:
std::list<int> indices;
};
template<class T>
class Traversal : public FactoryTraversal<T>
{
public:
Traversal();
void AddPoint(const T &x, const T &y, int index);
int GetResultXOR() const {return result_xor;}
private:
T coords_s[2];
T coords_e[2];
int result_xor;
void update_result(int index);
T calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2);
};
template<class T>
Traversal<T>::Traversal():FactoryTraversal<T>()
{
//Do nothing
}
template<class T>
void Traversal<T>::AddPoint(const T &x, const T &y, int index)
{
if (0 == this->GetIndicesSize())
{
this->indices.push_front(index);
coords_s[0] = x; coords_s[1] = y;
coords_e[0] = x; coords_e[1] = y;
}
else
{
T d1 = this->calculate_distance(x,coords_s[0],y,coords_s[1]);
T d2 = this->calculate_distance(x,coords_e[0],y,coords_e[1]);
if (d1 < d2)
{
this->indices.push_front(index);
coords_s[0] = x; coords_s[1] = y;
}
else
{
this->indices.push_back(index);
coords_e[0] = x; coords_e[1] = y;
}
}
this->update_result(index);
}
template<class T>
T Traversal<T>::calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2)
{
if (typeid(T) == typeid(int))
{
return std::min(std::abs(x1-x2),std::abs(y1-y2));
}
return 0;
}
template<class T>
void Traversal<T>::update_result(int index)
{
if (0 == this->GetIndicesSize())
result_xor = index;
else
result_xor ^= index;
}
template<class T>
FactoryTraversal<T>::FactoryTraversal()
{
indices.clear();
}
template<class T>
FactoryTraversal<T>::~FactoryTraversal()
{
//Do Nothing
}
template<class T>
FactoryTraversal<T>* FactoryTraversal<T>::CreateInstance(const traversal_type &type)
{
if (TRAVERSAL == type)
return new Traversal<T>();
else
return NULL;
}
FactoryTraversal<int> factory_traversal;
Traversal<int> *traversal = new Traversal<int>();
int main()
{
int T;
std::cin>>T;
int output[T];
for (int i = 0; i < T; ++i)
{
int N;
std::cin>>N;
FactoryTraversal<int> factory_traversal;
FactoryTraversal<int> *traversal = factory_traversal.CreateInstance(TRAVERSAL);
for (int j = 0; j < N; ++j)
{
int x, y;
std::cin>>x>>y;
traversal->AddPoint(x,y,j+1);
}
Traversal<int> *tmp = dynamic_cast<Traversal<int> *>(traversal);
if (tmp)
output[i] = tmp->GetResultXOR();
else
output[i] = 0;
}
for (int i = 0; i < T; ++i)
{
std::cout<<output[i]<<std::endl;
}
return 0;
}
Interfaces in C++ are called "abstract classes", and classes are abstract if they have at least one "pure virtual function". A function is a pure virtual function if it is prefixed with virtual and has a trailing =0 in its declaration. This is what you want for FactoryTraversal::AddPoint:
virtual void AddPoint(const T &x, const T &y, int index) = 0;
Now the derived class is expected to define it (and it does). Without AddPoint being pure virtual, you are forced to provide an implementation for it in the base class, which you could do simply as:
virtual void AddPoint(const T &x, const T &y, int index){}
This gives a "default" or fallback implementation for when a derived class chooses not to override the method. If it were pure virtual, the derived class is forced to define it, lest a call to it result in a compiler error (otherwise the derived class is also considered abstract).
Note that destructors should never be pure virtual. The way you have it right now is great; you unconsciously followed the rules I've outlined above.
Some other notes:
Variable length arrays are not legal C++, this is a compiler extension:
int output[T]; // T is read from command line
Use a vector instead:
std::vector<int> output(T);
You have memory leaks as-is. Use a managed pointer like unique_ptr so you don't have to worry about new and delete
I stated that you wanted AddPoint to be pure virtual and I mean it. You code won't compile if that's the first step you take, though. It looks like you merged a base class and a factory into one; split those out.
Putting it all together we can define our new base class as:
template<class T>
class TraversalBase
{
public:
virtual ~TraversalBase(){}
const std::list<int>& GetIndices() const {return indices;}
int GetIndicesSize() const {return indices.size();}
virtual void AddPoint(const T &x, const T &y, int index) = 0;
protected:
std::list<int> indices;
};
The derived class becomes (very little change, also notice the override keyword):
template<class T>
class Traversal : public TraversalBase<T>
{
public:
void AddPoint(const T &x, const T &y, int index) override;
int GetResultXOR() const {return result_xor;}
private:
T coords_s[2];
T coords_e[2];
int result_xor;
void update_result(int index);
T calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2);
};
And our Factory class is much simplified:
template <class T>
struct FactoryTraversal
{
FactoryTraversal(){}
std::unique_ptr<TraversalBase<T>> CreateInstance(const traversal_type &type);
~FactoryTraversal(){}
};
Live Demo (C++11)
I'm trying to map data types from a file to memory, so I have a class which takes the information for each column.
Different types have different mapping parameters, so I created a struct with the appropriate parameters for each supported type. I managed to solve the problem of having typesafety this way, and now I'm using a template for i.e. numeric types which all share the same attributes, and only the type differs.
The only thing that is is still rather ugly, is that I can not assign the correct enum simply based on the supported type alone.
As is shown in the example below, in case of a numeric type I manually have to assign the associated type (c5 and c6 in the example code). Now I'm wondering if there is a more elegant solution, so that I can use some template technique (enable_if?)to select the correct enum value based on the supported type alone (c7 is the intended target example).
I'm using Visual Studio 2010 which supports a subset of C+11.
#define _CRT_SECURE_NO_WARNINGS
#include <time.h>
#include <type_traits>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
typedef char byte_t;
typedef unsigned char ubyte_t;
typedef short word_t;
typedef unsigned short uword_t;
typedef unsigned short date_t;
typedef char string_t;
class ColumnDef
{
public:
typedef enum
{
T_UNDEFINED,
T_byte,
T_ubyte,
T_word,
T_uword,
T_size_t,
T_string,
T_std_string,
T_date_string,
T_date,
T_MAX
} ColumnDefType;
typedef enum
{
DF_UNDEFINED,
DF_TTMMYY,
DF_YYMMTT,
DF_TTMMYYYY,
DF_YYYYMMTT,
DF_TT_MM_YYYY,
DF_YYYY_MM_TT,
DF_MAX
} DateFormat;
class cstring_type
{
public:
ColumnDefType Type;
const char *Adress;
size_t MaxLen;
static cstring_type init(const char *p, size_t nMaxLen) { cstring_type t = {T_string, p, nMaxLen}; return t; };
};
class cpp_string_type
{
public:
ColumnDefType Type;
std::string *Adress;
static cpp_string_type init(std::string *p) { cpp_string_type t = {T_std_string, p}; return t; };
};
class ubyte_type
{
public:
ColumnDefType Type;
ubyte_t *Adress;
ubyte_t Default;
static ubyte_type init(ubyte_t *p, ubyte_t nDef) { ubyte_type t = {T_ubyte, p, nDef}; return t; };
};
class date_type
{
public:
ColumnDefType Type;
date_t *Adress;
date_t Default;
DateFormat Format;
static date_type init(date_t *p, date_t nDef, DateFormat fmt) { date_type t = {T_date, p, nDef, fmt}; return t; };
};
template <typename T, ColumnDefType E>
class numeric
{
public:
ColumnDefType Type;
T *Adress;
T Default;
static numeric<T, E> init(T *p, T nDef) { numeric<T, E> t = {E, p, nDef}; return t; };
};
public:
ColumnDef(void) { mType = T_UNDEFINED; }
ColumnDef(ubyte_type const &t) { mType = t.Type; ub = t; }
ColumnDef(date_type const &t) { mType = t.Type; d = t; }
ColumnDef(cpp_string_type const &t) { mType = t.Type; cps = t; }
ColumnDef(cstring_type const &t) { mType = t.Type; cs = t; }
ColumnDef(numeric<size_t, T_size_t> const &t) { mType = t.Type; st = t; }
ColumnDef(numeric<byte_t, T_byte> const &t) { mType = t.Type; b = t; }
virtual ~ColumnDef(void)
{
}
void func(ColumnDefType nType)
{
switch(nType)
{
case T_byte:
{
byte_t *p = b.Adress;
if(!p)
break;
}
break;
case T_size_t:
{
size_t *p = st.Adress;
if(!p)
break;
}
break;
case T_ubyte:
{
ubyte_t *p = ub.Adress;
if(!p)
break;
}
break;
default:
std::cout << "Unknown" << std::endl;
break;
}
}
private:
ColumnDefType mType;
union
{
ubyte_type ub;
date_type d;
cpp_string_type cps;
cstring_type cs;
numeric<size_t, T_size_t> st;
numeric<byte_t, T_byte> b;
};
};
int main()
{
std::string s = "value";
date_t dt;
char tst[5];
size_t n;
byte_t b;
// Correct examples
ColumnDef c0(ColumnDef::date_type::init(&dt, 0, ColumnDef::DF_YYYY_MM_TT));
ColumnDef c1(ColumnDef::cstring_type::init(tst, sizeof(tst)));
ColumnDef c2(ColumnDef::cpp_string_type::init(&s));
ColumnDef c3(ColumnDef::numeric<byte_t, ColumnDef::T_byte>::init(&b, 0));
ColumnDef c4(ColumnDef::numeric<size_t, ColumnDef::T_size_t>::init(&n, 0));
// Wrong intialization causes a compiler error because type doesn't match enum. Only T_size_t should be allowed here.
ColumnDef c5(ColumnDef::numeric<size_t, ColumnDef::T_std_string>::init(&n, 0));
ColumnDef c6(ColumnDef::numeric<size_t, ColumnDef::T_byte>::init(&n, 0));
ColumnDef c7(ColumnDef::numeric<size_t>::init(&n, 0)); // should assign the correct type automatically inferred by the supported type
return 0;
}
You can just write map between types and enum values, and then reuse it in your code:
namespace details {
template <typename T> struct TypeToEnum;
template <>
struct TypeToEnum<size_t> {
static const ColumnDef::ColumnDefType value = ColumnDef::T_size_t;
};
template <>
struct TypeToEnum<char> {
static const ColumnDef::ColumnDefType value = ColumnDef::T_byte;
};
}
template <typename T>
ColumnDef::numeric<T> ColumnDef::numeric<T>::init(T *p, T nDef)
{
ColumnDef::numeric<T> t = {details::TypeToEnum<T>::value, p, nDef};
return t;
}
I am wring a generic class to extract something of type SrcT by a string key, convert it to type TargetT and then return. Like:
class Foo
{
public:
bool get(const char* key, std::string& str)
{
if (std::string(key) == "found")
{
str = "stringA";
return true;
}
return false;
}
bool get(const char* key, int& a)
{
a = 100;
return true;
}
};
class Bar
{
public:
template <typename Converter>
typename Converter::result_type extract(const char* key, Converter converter)
{
typedef typename Converter::first_argument_type SrcT; // <- HERE IS THE ERROR
typedef typename Converter::result_type TargetT;
SrcT temp;
if (_foo.get(key, temp))
{
TargetT target = converter(temp);
return target;
}
else
{
throw std::runtime_exception("ah");
}
}
Foo _foo;
};
struct Converters
{
static int toInt(const std::string& str) { return str.size(); }
static float toFloat(int a) { return 100.0 + a; }
};
BOOST_AUTO_TEST_CASE(Nothing)
{
Bar bar;
const int saveHere = bar.extract("found", boost::bind(&Converters::toInt, _1));
BOOST_CHECK_EQUAL(saveHere, 7); // 7=sizeof("stringA")
}
TargetT was deduced from Converter type, but no clue about SrcT.
Any help is appreciated.
UPDATE
After checking boost/bind.hpp and boost/bind/bind_template.hpp, looks like no such thing was exposed.
Try with:
typedef typename boost::function_traits<Converter>::arg1_type SrcT;
Is there anyways to fusion::for_each() to iterate through a1 and a2 in a BOOST_FUSION_ADAPT_ADT or BOOST_FUSION_ADAPT_ASSOC_ADT, just like if adapted using BOOST_FUSION_ADAPT_STRUCT?
class A
{
private:
int a1_;
double a2_;
public:
void set_a1(int v) { a1_ = v; }
int get_a1() const { return a1_; }
void set_a2(double v) { a2_ = v; }
double get_a2() const { return a2_; }
};
BOOST_FUSION_ADAPT_ASSOC_ADT(
A,
(int, int, obj.get_a1(), obj.set_a1(val) )
(double, double, obj.get_a2(), obj.set_a2(val) )
)
struct Print
{
template <typename T>
void operator()( T& t ) const
{
// T is of type adt_attribute_proxy
// cout << ??
// would like to print a1 and a2 value
}
};
int main()
{
A a;
boost::fusion::for_each( a, Print() );
}
adt_attribute_proxy provides method get to access attribute value.
struct Print
{
template <typename T>
void operator()(T& t) const
{
std::cout << t.get();
}
};
P.S. There are errors in you sample BOOST_FUSION_ADAPT_ASSOC_ADT macro. Each element should be declared with 5 params (attribute_typeN, attribute_const_typeN, get_exprN, set_exprN, key_typeN) Maybe you mix up BOOST_FUSION_ADAPT_ASSOC_ADT with BOOST_FUSION_ADAPT_ADT?