Destructor for template class - c++

I have template class. One of the parameters is either char* or std::string. So I have to delete char*, and dont deletestd::string`. I have no idea what I should do.
template <typename T>
class Discipline
{
public:
unsigned int getLectureHours() const { return lecture_hours; }
unsigned int getTotalHours() const { return total_hours; }
unsigned int getPracticalHours() const { return practical_hours; }
unsigned int getSelfHours() const { return self_hours; }
T getName() const { return name; }
Date& getDate() const { return date; }
Discipline() : date(1,1,2000), name("Math"), total_hours(10), lecture_hours(4), practical_hours(4), self_hours(2) {}
Discipline(Date* tdate, T& tname, int& t1, int& t2, int& t3) : date(*tdate), name(tname), total_hours(t1), lecture_hours(t2), practical_hours(t3), self_hours(t1-t2-t3){}
Discipline(const Discipline<T>& other)
{
*this = other;
name = "def";
}
Discipline<char*>& operator=(const Discipline<char*>& param)
{
if (this != &param)
{
this->name = new char[strlen(param.name)+1];
strcpy(this->name, param.name);
this->date = param.date;
this->total_hours = param.total_hours;
this->lecture_hours = param.lecture_hours;
this->self_hours = param.self_hours;
this->practical_hours = param.practical_hours;
}
return *this;
}
Discipline<std::string>& operator=(const Discipline<std::string>& param)
{
if (this != &param)
{
// this->name = "";
// this->name += "def";
this->date = param.date;
this->total_hours = param.total_hours;
this->lecture_hours = param.lecture_hours;
this->self_hours = param.self_hours;
this->practical_hours = param.practical_hours;
}
return *this;
}
~Discipline<char*>() { delete[] name; }
private:
Date date;
T name;
unsigned int total_hours;
unsigned int lecture_hours;
unsigned int practical_hours;
unsigned int self_hours;
};

There is explicit specialization. In the implementation, you can go like
template<>
Discipline<string>::~Discipline(){}
template<>
Discipline<char*>::~Discipline(){
delete[] name;
}
This can be even done flexible:
template<class T>
Discipline<T>::~Discipline(){}
template<>
Discipline<char*>::~Discipline(){
delete[] name;
}
This variant would call delete on the class over char* and do nothing within the destructor in every other case, if you plan on adding more specializations in the future.
You might want to read http://en.cppreference.com/w/cpp/language/template_specialization
(Just to give an answer to the question as stated. Of course, the comment by antred is the actual solution.)

One variant is to add a simple static method , say DeleteTheString, with two argument overloads. Then you just call with your templated type value and let the compiler decide.
Another variant is to wrap the char* in a unique_ptr[], so it deletes itself. You could do that dynamically by having a little adaptor class SafeStore has member typedef std::string as, while SafeStore has the typedef std::unique_ptr<char[]> as.

Related

Make a Class variable const after declaration (run time) (with some class method)

I have a template:
template<typename T>
struct Parameter {
T value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
// Fix this->value (make this->value const)
}
void print() { std::cout << value << std::endl; }
};
and I would like at some point after initialization to 'const-ify' the value variable
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance.value = 2.3; // Not Allowed, throws error
Is it possible to do so and how?
If you want to maintain the same interface, and marshalling access to value through accessors is something you want to avoid, then you could isolate the "fixable" feature in its own dedicated type that implicitly converts to/from T:
template<typename T>
class fixable {
bool fixed_ = false;
T val_;
public:
fixable() = default;
fixable(T v) : val_(v) {}
fixable(const fixable&) = default;
fixable(fixable&&) = default;
operator const T&() const {
return val_;
}
fixable& operator=(const T& v) {
if(fixed_ ) {
throw std::runtime_error("Fixable has been fixed");
}
val_ = v;
return *this;
}
void fix() {
fixed_ = true;
}
};
You would then replace the T member with a fixable<T> within Parameter:
template<typename T>
struct Parameter {
fixable<T> value;
std::string name;
Parameter(std::string name, T value) : name(name), value(value){}
void fix() {
value.fix();
}
void print() { std::cout << value << std::endl; }
};
The main function from your question can remain exactly as-is.
You can use something like this:
Similar to abowe answer but with boolean inside the Parameter struct
template<typename T>
struct Parameter {
Parameter(std::string name, T value) : name(name), value(value), bFixed(false) {}
void fix() {
bFixed = true;
}
void print() { std::cout << value << std::endl; }
Parameter& operator=(const T& oValue)
{
if (bFixed)
{
throw std::runtime_error("Error fixed value..");
}
value = oValue;
return *this;
}
std::string name;
private:
bool bFixed;
T value;
};
int main()
{
std::string name = "variance";
double var = 1.0;
Parameter<double> variance(name, var);
variance.print();
variance.fix();
variance = 2.3; // Not Allowed, throws error
}
You cannot change a member variable from const to non-const. However, you can create a new object in which it is const. For example:
template<typename T>
struct example {
T value;
example<T const> fix() && {
return {value};
}
};
int main(){
auto x = example<int>{1};
x.value = 4; // OK
auto y = std::move(x).fix();
y.value = 7; // error: assignment of read-only member
}
The presence of && forces the use of std::move which makes it obvious that x should no longer be used.

How to use assignment operator on proxy of index operator

In the following code I made a template class, Its initialized in main function and I'm trying to assign char* as you can see below but It isn't working. I think the issue is in assign operator function I defined in Proxy class but I can't figure it out
#include <iostream>
using namespace std;
template <class T>
class Vector {
public:
T *p;
Vector(int size) {
p = new T[size];
}
class Proxy {
Vector &a;
int i;
public:
Proxy(Vector &a, int i) : a(a), i(i) {
}
void operator=(const T x) {
a.p[i] = x;
}
};
Proxy operator[](int i) {
return Proxy(*this, i);
}
};
int main() {
Vector<char *> sv1(2);
sv1[0] = "John";
sv1[1] = "Doe";
}
I'm getting following error;
I already tried setting parameter in assignment operator function to const, I also tried implicitly typecasting to T nothing has worked
Try this:
using namespace std;
template <class T>
class Vector {
public:
T* p;
int sz;
Vector(int size) {
p = new T[size];
sz = size;
}
template<class T>
class Proxy {
Vector<T>& v;
int i;
public:
Proxy(Vector<T>& vec, int index) :v(vec),i(index) { }
void operator= (const T val) { v.p[i] = val; }
};
Proxy<T> operator[](int index) { return Proxy<T>(*this, index); }
};
Your code will work with any basic type, (int, char, double) and pointers, but not, for example, with this:
int main() {
Vector<char*> sv1(2);
sv1[0] = "John";
sv1[1] = "Doe";
}
Firstly, the Vector points to a char*, not a string literal (const char*). You'd have to cast it using a C-style cast or a const_cast. Example:
int main() {
Vector<char*> sv1(2);
sv1[0] = const_cast<char*>("John"); //succeeds
sv1[1] = (char*)"Doe"; //succeeds
sv1[0] = "John"; //fails
sv1[1] = "Doe"; //fails
}
A string literal is always a const char* in C++.
You'll have same error writing code:
char * whatever = "something";
This code is absolutely wrong at least for string:
void operator=(const T x)
{
a.p[i] = x;
}
Step 1: allocate buffer;
Step 2: copy string to allocated buffer.
Your code is OK for primitives like char, int, etc. The following code should work:
int main() {
Vector<char> sv1(2);
sv1[0] = 'J';
sv1[1] = 'D';
}

dynamically call same named function with different return type

I have a situation here...
I want to design a Factory where I can call a function with same name and no parameters but return different data Types. Based on the SubClassName I need to instantiate the Object.
Need help or lead on any design pattern to follow?
EDIT:
An abstract pseudo code...
class parent{
public:
virtual string getName() = 0;
//some virtual function.. not sure how to design. As the return type is dynamic.
*** getValue(){}
};
class A : public parent{
int x;
public:
virtual string getName(){ return "A";}
virtual int getValue(){retun x;}
};
class B : public parent{
string s;
public:
virtual string getName(){ return "B";}
virtual string getValue(){ return s;}
};
void main(){
string callingClass = "B";
parent * arrayPtrs[2];
arrayPtrs[0] = new A;
arrayPtrs[1] = new B;
for (loop through array, through iterator i){
if(arrayPtrs[i]->getName == callingClass ){
cout<<arrayPtrs[i]->getValue;
}
}
}
In C++ a function can only have one return type at a time, and you cannot change that dynamically.
However - as suggested by #mch - you can use template specializations. Keep in mind though, that this method is not dynamic. Your functions will be generated at compile time.
If I understood your question correctly, maybe this can be of help.
class MyObject1
{
//...
};
class MyObject2
{
//...
};
template<typename T>
struct Factory
{
constexpr static T gen();
};
template<>
struct Factory<MyObject1>
{
constexpr static MyObject1 gen()
{
return MyObject1(/*... whatever parameters you see fit ...*/);
}
};
template<>
struct Factory<MyObject2>
{
constexpr static MyObject2 gen()
{
return MyObject2(/*... whatever parameters you see fit ...*/);
}
};
int main()
{
auto myObj = Factory<MyObject1>::gen();
return 0;
}
Although this method seems fairly useless to me. You could simply call the desired constructor instead of this.
But then again, I'm not sure if this is what you thought of. If I made any mistakes please feel free, to correct me. I'll try to edit my answer best as I can.
EDIT:
To keep the virtual functionality too, the only way I can think of is type erasure: see https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Erasure
The closest I could get to what you've asked for is this:
#include <iostream>
#include <string>
#include <any>
class parent {
public:
// you can use this too but I think type checking is more handy
// see in main function
/* virtual std::string getName() const = 0; */
virtual std::any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual std::any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual std::any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << std::any_cast<callingClass::value_type>(arrayPtrs[i]->getValue()) << std::endl;
}
return 0;
}
I hope this one helps.
Note, that I used dynamic_cast to check the correct type. If you know a better solution, you can use that, too. But under these circumstances I couldn't think of any better.
EDIT2:
#include <iostream>
#include <string>
#include <tuple>
class some
{
using id = size_t;
template<typename T>
struct type { static void id() { } };
template<typename T>
static id type_id() { return reinterpret_cast<id>(&type<T>::id); }
template<typename T>
using decay = typename std::decay<T>::type;
template<typename T>
using none = typename std::enable_if<!std::is_same<some, T>::value>::type;
struct base
{
virtual ~base() { }
virtual bool is(id) const = 0;
virtual base *copy() const = 0;
} *p = nullptr;
template<typename T>
struct data : base, std::tuple<T>
{
using std::tuple<T>::tuple;
T &get() & { return std::get<0>(*this); }
T const &get() const& { return std::get<0>(*this); }
bool is(id i) const override { return i == type_id<T>(); }
base *copy() const override { return new data{get()}; }
};
template<typename T>
T &stat() { return static_cast<data<T>&>(*p).get(); }
template<typename T>
T const &stat() const { return static_cast<data<T> const&>(*p).get(); }
template<typename T>
T &dyn() { return dynamic_cast<data<T>&>(*p).get(); }
template<typename T>
T const &dyn() const { return dynamic_cast<data<T> const&>(*p).get(); }
public:
some() { }
~some() { delete p; }
some(some &&s) : p{s.p} { s.p = nullptr; }
some(some const &s) : p{s.p->copy()} { }
template<typename T, typename U = decay<T>, typename = none<U>>
some(T &&x) : p{new data<U>{std::forward<T>(x)}} { }
some &operator=(some s) { swap(*this, s); return *this; }
friend void swap(some &s, some &r) { std::swap(s.p, r.p); }
void clear() { delete p; p = nullptr; }
bool empty() const { return p; }
template<typename T>
bool is() const { return p ? p->is(type_id<T>()) : false; }
template<typename T> T &&_() && { return std::move(stat<T>()); }
template<typename T> T &_() & { return stat<T>(); }
template<typename T> T const &_() const& { return stat<T>(); }
template<typename T> T &&cast() && { return std::move(dyn<T>()); }
template<typename T> T &cast() & { return dyn<T>(); }
template<typename T> T const &cast() const& { return dyn<T>(); }
template<typename T> operator T &&() && { return std::move(_<T>()); }
template<typename T> operator T &() & { return _<T>(); }
template<typename T> operator T const&() const& { return _<T>(); }
};
using any = some;
class parent {
public:
// you can use this too but I think type checking is more handy
/* virtual std::string getName() const = 0; */
virtual any getValue() const = 0;
};
class A : public parent {
public:
typedef int value_type;
private:
value_type x;
public:
A(value_type x) :
x(x)
{}
/* virtual std::string getName() const override { return "A"; } */
virtual any getValue() const override
{ return this->x; }
};
class B : public parent {
public:
typedef std::string value_type;
private:
value_type s;
public:
B(const value_type& s) :
s(s)
{}
/* virtual std::string getName() const override { return "B"; } */
virtual any getValue() const override
{ return this->s; }
};
int main(){
using callingClass = A;
parent* arrayPtrs[2];
arrayPtrs[0] = new A(42);
arrayPtrs[1] = new B("my string");
for (unsigned i = 0; i < sizeof(arrayPtrs) / sizeof(parent*); ++i)
{
// Note:
// dynamic cast will return nullptr if $callingClass
// is not a derived class
if (dynamic_cast<callingClass*>(arrayPtrs[i]))
std::cout << arrayPtrs[i]->getValue()._<callingClass::value_type>() << std::endl;
}
return 0;
}
This snipped is in case you cannot use C++17 features, and is based on:
any class

Same outer structure only one difference between functions

I have many functions that do roughly the same apart from the what variable the modify
struct example
{
std::string name;
std::string category;
};
using ObjName = std::string;
using Value = std::string;
bool updateName(const ObjName &name, const Value& value) ...
bool updateCategory(const ObjName &name,const Value& value)
{
// boost optional pointing to struct reference
auto obj = findOjb(name);
if (obj)
{
obj.get().category = value; // variable name changes
return true;
}
return false;
}
What I am wondering is what I can do to combine the code ?
I suspect it will involve templates maybe traites/functors but I am unsure of how to approach it any ideas ?
Reworking Daerst's code to remove that awful offsetof in favor of pointers-to-members...
struct example
{
std::string name;
std::string category;
};
bool updateVariable(const ObjName &name, std::string example::*member, std::string const &value)
{
// your code ...
// Access
rule.get().*member = value
// rest of your code
}
bool updateName(const ObjName &oldname, const ObjName& newName)
{
return updateVariable(name, &example::name, newName));
}
bool updateCategory(const ObjName &name, Category &cat)
{
return updateVariable(name, &example::category, cat));
}
You could use lambdas:
template <typename Accessor>
bool updateVariable(const ObjName& name, const Value& value, Accessor access) {
auto obj = findObj(name);
if (obj)
{
access(obj.get()) = value;
return true;
}
return false;
}
bool updateCategory(const ObjName& name, const Value& value) {
return updateVariable(name, value,
[](Example& e) -> Value& { return e.category; });
}
This is a bit more flexible than the pointer-to-member solution. You can make it even more flexible by having the lambda do the setting instead of returning a reference.
You could use something traits like:
#include <string>
#include <assert.h>
struct example
{
std::string name;
int category;
};
struct nameDesc
{
typedef std::string valuetype;
static void set(example& obj, const valuetype& val)
{
obj.name = val;
}
};
struct categoryDesc
{
typedef int valuetype;
static void set(example& obj, const valuetype& val)
{
obj.category = val;
}
};
example test; // just for testing...
example& findObj(const std::string &name)
{
// just for testing...
return test;
}
template <typename V>
bool update(const std::string &objName, const typename V::valuetype& value)
{
example& obj = findObj(objName);
V::set(obj, value);
return true;
}
bool updateName(const std::string &objName, const std::string& value) { return update<nameDesc>(objName, value); }
bool updateCategory(const std::string &objName, int value) { return update<categoryDesc>(objName, value); }
int main()
{
update<nameDesc>("objname", "asdf");
update<categoryDesc>("objname", 1234);
assert(test.name == "asdf");
assert(test.category == 1234);
updateName("objname", "qwer");
updateCategory("objname", 7890);
assert(test.name == "qwer");
assert(test.category == 7890);
return 0;
}
And I'd encourage you having a look at boost::spirit / BOOST_FUSION_ADAPT_STRUCT if possible.
A bit hacky, but this could be a solution (untested code) using offsetof:
struct example
{
std::string name;
std::string category;
};
bool updateVariable(const size_t offset, std::string value)
{
// your code ...
// ASSIGNMENT: get address, apply offset and assign value
*(&rule.get() + offset) = cat;
// rest of your code
}
bool updateName(const ObjName &oldname, const ObjName& newName)
{
return updateVariable(offsetof(struct example, name), newName));
}
bool updateCategory(const ObjName &name, Category &cat)
{
return updateVariable(offsetof(struct example, category), cat));
}
I assume that ObjName and Category are typedefs of string or can be implicitly converted.
You still need to add a one-liner function for each member variable, which is pretty hard to elude in C++ if you want to stick to a hard-coded struct. You might want to consider converting the whole struct definition to data, e.g. loaded from a file, opening other possibilities.

Partial specialization of member functions

I am having problems with a template specialization. Below are two classes, AbstractSetting (parent) and Setting (child). (AbstractSetting is probably not important, but I am including it for context.)
The ultimate goal of this code is to create a container to hold various INI settings of different types -- string, int, enum, etc. (DataType), that can be referenced with an enum (IndexType). There may be different index enums in different contexts (main game, test suite, server, etc.).
I am trying to create a series of fromString methods that, when passed a string, return an object of DataType (one of my template parameters).
The code as presented will compile but not link.
If I uncomment the assert, it will link, but none of the specializations are called, and the assert trips on every call to fromString, regardless of the parameters.
How can I make this work?
Note that U32, S32, etc. are types of ints.
template <class IndexType>
class AbstractSetting
{
private:
IndexType mName; // Value we use to look this item up
string mIniKey; // INI key
string mIniSection; // INI section
string mComment;
public:
// Constructor
AbstractSetting(IndexType name, const string &key,
const string &section, const string &comment):
mIniKey(key),
mIniSection(section),
mComment(comment)
{
mName = name;
}
~AbstractSetting() { /* Do nothing */ } // Destructor
IndexType getName() const { return mName; }
string getKey() const { return mIniKey; }
string getSection() const { return mIniSection; }
string getComment() const { return mComment; }
virtual void setValFromString(const string &value) = 0;
virtual string getValueString() const = 0; // Returns val as str
virtual string getDefaultValueString() const = 0; // Returns def val as str
};
////////////////////////////////////////
////////////////////////////////////////
template <class DataType, class IndexType>
class Setting : public AbstractSetting<IndexType>
{
typedef AbstractSetting Parent;
private:
DataType mDefaultValue;
DataType mValue;
public:
Setting(IndexType name, const DataType &defaultValue, const string &iniKey,
const string &iniSection, const string &comment):
Parent(name, iniKey, iniSection, comment),
mDefaultValue(defaultValue),
mValue(defaultValue)
{
// Do nothing
}
~Setting() { /* Do nothing */ }
// Templated declaration
DataType fromString(const string &val) ; //{ Assert(false, "Specialize me!"); }
// Specializations
template<string *> string
fromString(const string &val) { return val; }
template<S32 *> S32
fromString(const string &val) { return atoi(val.c_str()); }
template<U32 *>
U32 fromString(const string &val) { return atoi(val.c_str()); }
template<U16 *>
U16 fromString(const string &val) { return atoi(val.c_str()); }
template<DisplayMode *>
DisplayMode fromString(const string &val) { return stringToDisplayMode(val); }
template<YesNo *>
YesNo fromString(const string &val) { return stringToYesNo(val); }
template<RelAbs *>
RelAbs fromString(const string &val) { return stringToRelAbs(val); }
template<ColorEntryMode *>
ColorEntryMode fromString(const string &val) { return stringToColorEntryMode(val); }
template<GoalZoneFlashStyle *>
GoalZoneFlashStyle fromString(const string &val) { return stringToGoalZoneFlashStyle(val); }
template<Color *>
Color fromString(const string &val) { return Color::iniValToColor(val); }
void setValue(const DataType &value) { mValue = value; }
DataType getValue() const { return mValue; }
string getValueString() const { return toString(mValue); }
string getDefaultValueString() const { return toString(mDefaultValue); }
void setValFromString(const string &value) { setValue(fromString(value)); }
};
I found a solution!
Since it seems that member functions cannot be partially specialized, I solved the problem by creating a new class that does not use the IndexType parameter.
class Evaluator
{
public:
template <class DataType> DataType fromString(const string &val);
};
In the .cpp file, I added:
// Templated default - needs to be overriden
template<class DataType> DataType
Evaluator::fromString(const string &val) {
Assert(false, "Specialize me!");
return DataType();
}
// Specializations.
// NOTE: All template specializations must be declared in the namespace scope to be
// C++ compliant. Shame on Visual Studio!
template<> string
Evaluator::fromString(const string &val) { return val; }
template<> S32
Evaluator::fromString(const string &val) { return atoi(val.c_str()); }
template<> U32
Evaluator::fromString(const string &val) { return atoi(val.c_str()); }
template<> U16
Evaluator::fromString(const string &val) { return atoi(val.c_str()); }
template<> DisplayMode
Evaluator::fromString(const string &val) { return stringToDisplayMode(val); }
template<> YesNo
Evaluator::fromString(const string &val) { return stringToYesNo(val); }
template<> RelAbs
Evaluator::fromString(const string &val) { return stringToRelAbs(val); }
template<> ColorEntryMode
Evaluator::fromString(const string &val) { return stringToColorEntryMode(val); }
template<> GoalZoneFlashStyle
Evaluator::fromString(const string &val) { return stringToGoalZoneFlashStyle(val); }
template<> Color
Evaluator::fromString(const string &val) { return Color::iniValToColor(val); }
Then, in the Setting class, I replaced the similar block of code with this call:
DataType fromString(const string &val) {
return mEvaluator.fromString<DataType>(val);
}
This seems to work nicely, and is pretty readable.
If anyone is interested, the full code will be available at the link below, after it is more fully tested and checked in.
https://code.google.com/p/bitfighter/source/browse/zap/Settings.h