how to override base class with template child? - c++

I have the following code.
#include <string>
#include <map>
#include <utility>
#include <vector>
#include <cmath>
class Configuration {
protected:
static std::map<std::string, Configuration*> commands;
static std::vector<Configuration*> commidx;
const std::string name;
const int index;
int (*snippet)(float);
public:
Configuration(std::string name, const int index, int (*snippet)(float))
: name(std::move(name)), index(index), snippet(snippet) {}
virtual ~Configuration() = default;
virtual void set(float val) {} //should we raise an error?
virtual float get() { return NAN; } //should we raise an error?
};
template<typename T>
class Config : public Configuration {
const std::string type;
const std::string def;
T cur, min, max;
public:
explicit Config(const char *name, int index, const char *_type, const char *def, int (*snippet)(float), T min , T max)
: Configuration(name, index, snippet)
, type(_type)
, def(def)
, min(min)
, max(max)
{
if (type == "float") {
cur = std::stof(def);
} else if (type == "integer") {
cur = std::stoi(def);
} else if (type == "bool") {
cur = std::stof(def) != 0;
} else {
SPDLOG_ERROR("unknownt type {}", type);
}
}
void set(T val) override {
if (val < min) val = min;
if (val > max) val = max;
if (val != cur) {
val = cur;
snippet(val);
}
}
T get() override {
return cur;
}
};
std::vector<Configuration*> Configuration::commidx {
new Config<float>("fff", 0, "float", "0.4", nullptr, 0, 1),
new Config<bool>("bbb", 1, "bool", "0", nullptr, 0, 1),
new Config<integer>("iii", 8, "int", "0", nullptr, 0, 3),
};
This bombs in compilation because set() and get() methods don't really override base class.
How can I achieve desired result: put in the same vector of pointers to slightly different template classes?

You can try something like following.
#include <string>
#include <map>
#include <utility>
#include <vector>
#include <cmath>
class Configuration
{
protected:
static std::map<std::string, Configuration *> commands;
static std::vector<Configuration *> commidx;
const std::string name;
const int index;
int (*snippet)(float);
public:
Configuration(std::string name, const int index, int (*snippet)(float))
: name(std::move(name)), index(index), snippet(snippet) {}
virtual ~Configuration() = default;
};
template <typename T>
class ConfigurationBase : public Configuration
{
public:
ConfigurationBase(std::string name, const int index, int (*snippet)(float))
: Configuration(name, index, snippet)
{
}
//virtual void set(T val) {}
//virtual T get() { return NAN; }
virtual void set(T val) = 0;
virtual T get() = 0;
};
template <typename T>
class Config : public ConfigurationBase<T>
{
const std::string type;
const std::string def;
T cur, min, max;
public:
explicit Config(const char *name, int index, const char *_type, const char *def, int (*snippet)(float), T min, T max)
: ConfigurationBase<T>(name, index, snippet), type(_type), def(def), min(min), max(max)
{
if (type == "float")
{
cur = std::stof(def);
}
else if (type == "integer")
{
cur = std::stoi(def);
}
else if (type == "bool")
{
cur = std::stof(def) != 0;
}
else
{
// SPDLOG_ERROR("unknownt type {}", type);
}
}
void set(T val) override
{
if (val < min)
val = min;
if (val > max)
val = max;
if (val != cur)
{
val = cur;
// snippet(val);
}
}
T get() override
{
return cur;
}
};
std::vector<Configuration *> Configuration::commidx{
new Config<float>("fff", 0, "float", "0.4", nullptr, 0, 1),
new Config<bool>("bbb", 1, "bool", "0", nullptr, 0, 1),
new Config<int>("iii", 8, "int", "0", nullptr, 0, 3),
};

Related

I'm not able to delete elements of these vectors

I want to delete every element at a certain index (that corresponds to a certain content), but I'm getting a segmentation fault... This is the structure of my code and the method deleteRecord is what I've tried but doesn't work:
class Tab {
public:
Tab();
~Tab() {};
bool colIsPresent(const string & col_name);
template <typename S> void deleteRecord(S & content, const string & col_name) {
int delete_pos;
if (!this->colIsPresent(col_name)) return;
const auto & it_columns = _columns.find(col_name);
if (it_columns != _columns.end()) {
auto ci = dynamic_cast<ColumnImpl<S> *>(it_columns->second.get());
if (ci != nullptr) {
for (int i = 0; i < ci->getData().size(); i++) {
if (ci->getData()[i] == content) {
delete_pos = i;
}
for (auto & it_columns_2 : _columns) {
auto ci2 = dynamic_cast<ColumnImpl<S> *>(it_columns_2.second.get());
ci2->getData().erase(ci2->getData().begin() + delete_pos);
}
}
}
}
}
private:
map<string, shared_ptr<Column>> _columns;
};
template <typename T> class ColumnImpl : public Column {
public:
ColumnImpl() : Column() {}
ColumnImpl(const T& to_set);
vector<T> & getData() { return _data; }
protected:
vector<T> _data;
};
class Column {
public:
Column();
virtual ~Column() {};
virtual string getType() = 0;
};
class Database {
public:
Database();
~Database();
bool tabIsPresent(const string & tab_name);
template <typename S> void deleteRecordFromTab(const string & tab_name, S & content, const string & col_name) {
const auto & it_target_tab = _tables.find(tab_name);
it_target_tab->second.deleteRecord(content, col_name);
}
private:
map<string, Tab> _tables;
};
Reproducible example:
Database data_base;
string tab = "EX_TAB", str1 = "STR_EX1", str2 = "STR_EX2", age = "AGE", name = "NAME", integer = "INT", text = "TEXT";
int a = 17, b = 18;
data_base.createNewTable(tab);
data_base.addColumnToTab(tab, age, integer);
data_base.addColumnToTab(tab, name, text);
data_base.addElemToColOfTab(tab, age, a);
data_base.addElemToColOfTab(tab, age, b);
data_base.addElemToColOfTab(tab, name, str1);
data_base.addElemToColOfTab(tab, name, str2);
data_base.deleteRecordFromTab(tab, str1, name);
// createNewTable creates a new table
// addColumnToTab adds a new column of the right type to _columns
// addElemToColumnOfTab adds an element to the targeted column

why do i keep getting this error: invalid initialization of non-const reference of type 'FarmAnimal&' from an rvalue of type 'FarmAnimal'|

#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
class FarmAnimal {
public:
FarmAnimal(double water_consumption);
double getwaterConsumption();
// ...
private:
double water_consumption;
};
FarmAnimal::FarmAnimal(double water_consumption) {
this->water_consumption = water_consumption;
}
double FarmAnimal::getwaterConsumption() {
return water_consumption;
}
class ConsumptionAccumulator
{
public: ConsumptionAccumulator();
double getTotalConsumption();
void addConsumption(FarmAnimal& animal);
private:
double total_consumption;
};
ConsumptionAccumulator::ConsumptionAccumulator() :
total_consumption(0)
{
}
double ConsumptionAccumulator::getTotalConsumption()
{
return total_consumption;
}
void ConsumptionAccumulator::addConsumption(FarmAnimal& animal)
{
total_consumption += animal.getwaterConsumption();
}
class Cow : public FarmAnimal
{
public: Cow(double weigth) : FarmAnimal(0.086 * weigth) {}
};
class Sheep : public FarmAnimal {
public:
Sheep(double weigth) : FarmAnimal(0.11 * weigth) {}
};
class Horse : public FarmAnimal {
public:
Horse(double weigth) : FarmAnimal(0.068 * weigth) {}
};
int main()
{
ConsumptionAccumulator accumulator;
double weigth = 0;
std::string input = "";
do
{
std::getline(cin, input);
if (1 == sscanf(input.c_str(), "cow %lf", &weigth))
{
accumulator.addConsumption((Cow)(weigth));
}
else if (1 == sscanf(input.c_str(), "sheep% lf", &weigth))
{
accumulator.addConsumption(Sheep(weigth));
}
else if (1 == sscanf(input.c_str(), "horse% lf", &weigth))
{
accumulator.addConsumption(Horse(weigth));
}
} while (input != "");
cout << accumulator.getTotalConsumption() << endl;
return 0;
}
Change this
void ConsumptionAccumulator::addConsumption(FarmAnimal& animal)
{
total_consumption += animal.getwaterConsumption();
}
to this
void ConsumptionAccumulator::addConsumption(const FarmAnimal& animal)
{
total_consumption += animal.getwaterConsumption();
}
C++ has a rule that you cannot bind a non-const reference to a temporary object. When you call addConsumption here
accumulator.addConsumption((Cow)(weigth));
you are creating a temporary Cow object and trying to use that to call addConsumption but it doesn't work because of the rule I mentioned.
Don't ignore const in C++. Use const references when you can, and declare methods as const if that's what they are.

c++ can not get value from map

I have implemented a serializer to send data over network. And I have implemented a system that can deserialize primitive data, string, map(string, string), map(string, float), but the error happens with map(string, int) when the deserialized map is used to fetch the value from key. In the debugger I can see that map receive correct value but when I'm trying to get data, I get an error "std::out_of_range at memory location".
Here is my code
#include <stdint.h>
#include <memory>
#include <string>
#include <map>
#include <algorithm>
#define STREAM_ENDIANNESS 0
#define PLATFORM_ENDIANNESS 0
using namespace std;
class OutputMemoryStream
{
void ReallocBuffer(uint32_t inNewLength)
{
mBuffer = static_cast<char*>(std::realloc(mBuffer, inNewLength));
mCapacity = inNewLength;
}
char* mBuffer = nullptr;
uint32_t mHead;
uint32_t mCapacity;
public:
OutputMemoryStream() : mHead(0) { ReallocBuffer(32); }
~OutputMemoryStream()
{
if (mBuffer) { mBuffer = nullptr; }
}
char* GetBufferPtr() const { return mBuffer; }
uint32_t GetLength() const { return mHead; }
void Write(const void* inData, size_t inByteCount)
{
//make sure we have space...
uint32_t resultHead = mHead + static_cast<uint32_t>(inByteCount);
if (resultHead > mCapacity)
{
ReallocBuffer(std::max(mCapacity * 2, resultHead));
}
//copy into buffer at head
std::memcpy(mBuffer + mHead, inData, inByteCount);
//increment head for next write
mHead = resultHead;
}
template< typename T > void Write(T inData)
{
static_assert(std::is_arithmetic< T >::value || std::is_enum< T >::value, "Generic Write only supports primitive data types");
if (STREAM_ENDIANNESS == PLATFORM_ENDIANNESS)
{
Write(&inData, sizeof(inData));
}
else { }
}
template< typename T >
void Write(const std::map< string, T >& inMap)
{
uint32_t elementCount = inMap.size();
Write(elementCount);
for (std::pair<string, T> element : inMap)
{
Write(element.first);
Write(element.second);
}
}
void Write(const std::string& inString)
{
size_t elementCount = inString.size();
Write(elementCount + 1);
Write(inString.data(), (elementCount + 1) * sizeof(char));
}
};
class InputMemoryStream
{
private:
char* mBuffer;
uint32_t mHead;
uint32_t mCapacity;
public:
InputMemoryStream() {}
InputMemoryStream(char* inBuffer, uint32_t inByteCount) : mBuffer(inBuffer), mCapacity(inByteCount), mHead(0) { }
~InputMemoryStream()
{
if (mBuffer) { mBuffer = nullptr; }
}
uint32_t GetRemainingDataSize() const
{
return mCapacity - mHead;
}
void Read(void* outData, uint32_t inByteCount)
{
uint32_t resultHead = mHead + inByteCount;
if (resultHead > mCapacity)
{
//handle error, no data to read!
//...
}
std::memcpy(outData, mBuffer + mHead, inByteCount);
mHead = resultHead;
}
template< typename T > void Read(T& outData)
{
static_assert(std::is_arithmetic< T >::value || std::is_enum< T >::value, "Generic Read only supports primitive data types");
Read(&outData, sizeof(outData));
}
template<typename T1>
void Read(std::map<string, T1> &mapP)
{
size_t elemenCount;
Read(elemenCount);
for (int i = 0; i < elemenCount; i++)
{
string key; T1 value;
Read(key);
Read(value);
std::pair<string, T1> pair(key, value);
mapP.insert(pair);
}
}
void Read(string &outString)
{
size_t strSize;
Read(strSize);
outString.resize(strSize);
for (int i = 0; i < strSize; i++)
{
Read(&outString[i], 1);
}
}
};
class ServerObject
{
OutputMemoryStream outStream;
InputMemoryStream inStream;
map<std::string, int> mapInt;
public:
ServerObject() {};
ServerObject(char* byteArray, int byteCount)
{
InputMemoryStream inStream(byteArray, byteCount);
Deserialize(inStream);
}
~ServerObject() {};
void Serialize()
{
outStream.Write(mapInt);
}
void Deserialize(InputMemoryStream inStream)
{
inStream.Read(mapInt);
}
OutputMemoryStream GetOutStream()
{
return outStream;
}
int GetInt(string key)
{
return mapInt.at(key);
}
void PutInt(string key, int value)
{
mapInt.insert(std::pair<string, int>(key, value));
}
};
int main()
{
ServerObject * so = new ServerObject();
so->PutInt("test", 10);
so->Serialize();
ServerObject * so1 = new ServerObject(so->GetOutStream().GetBufferPtr(), so->GetOutStream().GetLength());
int i = so1->GetInt("test");
system("pause>NULL");
return 0;
}
Your void Write(const std::string& inString) function of OutputMemoryStream should not store additional byte of buffer for null terminator because std::string will not contain null terminator but if you use c_str(), a null terminator will be included in the return from this method. Don't get confused with the internal structure of the memory. std::string stores the length of the string in its member variable so there is no need of null terminator. The function should be as shown below.
void Write(const std::string& inString)
{
size_t elementCount = inString.size();
Write(elementCount);
Write(inString.data(), elementCount * sizeof(char));
}

Can BOOST_FOREACH be customized for a pointer type?

I'm writing C++98 (sorry), but working with a C library, which has many objects stored in data structures of the form:
struct c_container
{
size_t len;
int data[1];
};
struct c_container *make_container(size_t n)
{
if (n == 0)
return NULL;
struct c_container *rv = (struct c_container *)malloc(sizeof(rv->len) + n*sizeof(rv->data));
rv->len = n;
return rv;
}
I'd like to do C++-style iteration using BOOST_FOREACH, but this doesn't work. (The "old style" of manually calling the range_begin and range_end functions does work).
inline int *range_begin(c_container *c)
{
return c ? &c->data[0] : NULL;
}
inline int *range_end(c_container *c)
{
return c ? &c->data[c->len] : NULL;
}
inline const int *range_begin(const c_container *c)
{
return c ? &c->data[0] : NULL;
}
inline const int *range_end(const c_container *c)
{
return c ? &c->data[c->len] : NULL;
}
namespace boost
{
template<>
struct range_mutable_iterator<c_container *>
{
typedef int *type;
};
template<>
struct range_const_iterator<c_container *>
{
typedef const int *type;
};
}
int main()
{
c_container *coll = make_container(3);
coll->data[0] = 1;
coll->data[1] = 42;
coll->data[2] = -1;
BOOST_FOREACH(int i, coll)
{
std::cout << i << std::endl;
}
}
This is all that should be necessary, according to http://www.boost.org/doc/libs/1_65_1/doc/html/foreach/extensibility.html (and I've tested it with classes)
However, that example uses a class, whereas I'm using a pointer to a class. Based on my investigation, it appears to be using the codepath that is only intended for const char * and const wchar_t *:
In file included from boost-foreach.cpp:6:0:
/usr/include/boost/foreach.hpp: In function ‘bool boost::foreach_detail_::done(const boost::foreach_detail_::auto_any_base&, const boost::foreach_detail_::auto_any_base&, boost::foreach_detail_::type2type<T*, C>*) [with T = c_container, C = mpl_::bool_<false>, const boost::foreach_detail_::auto_any_base& = const boost::foreach_detail_::auto_any_base&]’:
boost-foreach.cpp:65:5: instantiated from here
/usr/include/boost/foreach.hpp:749:57: error: no match for ‘operator!’ in ‘!* boost::foreach_detail_::auto_any_cast [with T = c_container*, C = mpl_::bool_<false>, typename boost::mpl::if_<C, const T, T>::type = c_container*, const boost::foreach_detail_::auto_any_base& = const boost::foreach_detail_::auto_any_base&](((const boost::foreach_detail_::auto_any_base&)((const boost::foreach_detail_::auto_any_base*)cur)))’
/usr/include/boost/foreach.hpp:749:57: note: candidate is: operator!(bool) <built-in>
Is there some additional boost trait to specialize or something?
It seems to be difficult to define the range functions for pointer types. But you can define them for c_container directly. The code looks like this:
#include <cstdlib>
#include <iostream>
#include <boost/foreach.hpp>
struct c_container
{
size_t len;
int data[1];
};
struct c_container *make_container(size_t n)
{
if (n == 0)
return NULL;
struct c_container *rv = (struct c_container *)malloc(sizeof(rv->len) + n * sizeof(rv->data));
rv->len = n;
return rv;
}
inline int *range_begin(c_container &c)
{
return c.len > 0 ? &c.data[0] : NULL;
}
inline int *range_end(c_container &c)
{
return c.len > 0 ? &c.data[c.len] : NULL;
}
inline const int *range_begin(const c_container &c)
{
return c.len > 0 ? &c.data[0] : NULL;
}
inline const int *range_end(const c_container &c)
{
return c.len > 0 ? &c.data[c.len] : NULL;
}
namespace boost
{
template<>
struct range_mutable_iterator<c_container>
{
typedef int *type;
};
template<>
struct range_const_iterator<c_container>
{
typedef const int *type;
};
}
#define MY_FOREACH(x, y) BOOST_FOREACH(x, *y)
int main()
{
c_container *coll = make_container(3);
coll->data[0] = 1;
coll->data[1] = 42;
coll->data[2] = -1;
//BOOST_FOREACH(int i, *coll)
MY_FOREACH(int i, coll)
{
std::cout << i << std::endl;
}
}
Note that the BOOST_FOREACH loop does not iterate over a pointer type. As a workaround you may define your own FOREACH that does so as shown in the code above.

In member function 'virtual void ... TestBody()'

edit*: The full error message: test_huffman.cpp: In member function 'virtual void HuffmanTest_Test_Test::TestBody()'
I'm trying to write a google test for some cpp code. I'm getting an error and I'm not sure how to fix it. This is the error: test_huffman.cpp: In member function 'virtual void HuffmanTest_Test_Test::TestBody()'. The only answer I found online is that I need an argument list? Not sure where to go from here. The huffman.h/.cpp are probably not necessary but figured I'd share them (no I didn't write them they are open source);
Here is the code that I get the error when I compile (w/ gcc):
#include "gtest/gtest.h"
#include "huffman.h"
TEST(HuffmanTest, Test)
{
char* words[3];
words[0] = "one\0";
words[1] = "two\0";
words[2] = "three\0";
int frequencies[UniqueSymbols] = {0};
for(int i = 1; i < 3; i++)
{
const char* ptr = words[i];
while (*ptr != '\0')
++frequencies[*ptr++];
}
INode* root = BuildTree(frequencies);
HuffCodeMap codes;
GenerateCodes(root, HuffCode(), codes);
delete root;
EXPECT_FALSE(codes.empty());
}
Huffman.h (open source):
#ifndef huffman_h_INCLUDED
#define huffman_h_INCLUDED
#include <iostream>
#include <queue>
#include <map>
#include <climits> // for CHAR_BIT
#include <iterator>
#include <algorithm>
const int UniqueSymbols = 1 << CHAR_BIT;
typedef std::vector<bool> HuffCode;
typedef std::map<char, HuffCode> HuffCodeMap;
class INode
{
public:
const int f;
virtual ~INode();
protected:
INode(int f);
};
class InternalNode : public INode
{
public:
INode *const left;
INode *const right;
InternalNode(INode* c0, INode* c1);
~InternalNode();
};
class LeafNode : public INode
{
public:
const char c;
LeafNode(int f, char c);
};
struct NodeCmp
{
bool operator()(const INode* lhs, const INode* rhs) const;
};
INode* BuildTree(const int (&frequencies)[UniqueSymbols]);
void GenerateCodes(const INode* node, const HuffCode& prefix, HuffCodeMap& outCodes);
#endif // huffman_h_INCLUDED
huffman.cpp (open source):
#include "huffman.h"
INode :: ~INode()
{
}
INode :: INode(int f)
: f(f)
{
}
InternalNode :: InternalNode(INode* c0, INode* c1)
: INode(c0->f + c1->f), left(c0), right(c1)
{
}
InternalNode :: ~InternalNode()
{
delete left;
delete right;
}
LeafNode :: LeafNode(int f, char c)
: INode(f), c(c)
{
}
bool NodeCmp :: operator()(const INode* lhs, const INode* rhs) const { return lhs->f > rhs->f; }
INode* BuildTree(const int (&frequencies)[UniqueSymbols])
{
std::priority_queue<INode*, std::vector<INode*>, NodeCmp> trees;
for (int i = 0; i < UniqueSymbols; ++i)
{
if(frequencies[i] != 0)
trees.push(new LeafNode(frequencies[i], (char)i));
}
while (trees.size() > 1)
{
INode* childR = trees.top();
trees.pop();
INode* childL = trees.top();
trees.pop();
INode* parent = new InternalNode(childR, childL);
trees.push(parent);
}
return trees.top();
}
void GenerateCodes(const INode* node, const HuffCode& prefix, HuffCodeMap& outCodes)
{
if (const LeafNode* lf = dynamic_cast<const LeafNode*>(node))
{
outCodes[lf->c] = prefix;
}
else if (const InternalNode* in = dynamic_cast<const InternalNode*>(node))
{
HuffCode leftPrefix = prefix;
leftPrefix.push_back(false);
GenerateCodes(in->left, leftPrefix, outCodes);
HuffCode rightPrefix = prefix;
rightPrefix.push_back(true);
GenerateCodes(in->right, rightPrefix, outCodes);
}
}