I am constructing a template structure and I need some trick to do the following:
I have a singly and two dimensional linked list, and I need first construct every node with no data in them after that I have to fill them with the data from a file. So I need if(x == UNINITIALIZED OR NOT) since the data could be string, int and double. I couldn't find a common null initializer just for that if check. I hope there is a way to do this.
I tried if(x == NULL), if(x == 0), if(x == ""), if(x == void). None of them worked.
if your node represents one of the types specified, you could simply use a template, template specialization, or overloading.
If you only have those three types, you could create specialized initializer functions for the known types.
template <class T>
class CNode {
public:
CNode() {
Init(m_Value);
}
private:
T m_Value;
static void Init(T n) { n = 0; } // Default catch for types that can be set to 0/NULL
static void Init(bool b) { b = false; }
static void Init(string str) { str = ""; }
};
Of course there are also ways of specifying type specifics for templated functions, but I don't remember that offhand. I know Boost uses those, it would be a way of specifying additional methods of initialization outside of the original definition.
As far as I understand your problem, I think the following code shows possible and interesting solution which uses two Boost libraries: Optional and Tuple:
#include <cassert>
#include <algorithm>
#include <iterator>
#include <list>
#include <string>
#include <boost/optional.hpp>
#include <boost/tuple/tuple.hpp>
int main()
{
typedef boost::tuple<std::string, double, int> value_t;
typedef boost::optional<value_t> node_t;
std::list<node_t> nodes;
// first construct every node with no data in them
std::fill_n(std::inserter(nodes, nodes.begin()), 5, node_t());
// check all nodes have not been initialized yet, so they are in "null" state
auto it = nodes.cbegin();
while (it != nodes.cend())
{
assert(!it->is_initialized());
++it;
}
// add non-null initialized node
// or fill with the data from a file, etc.
node_t n("abc");
nodes.insert(it, n);
assert(nodes.back().is_initialized());
}
Related
I'm trying to write something similar to this:
void loadImage(SDL_Renderer *ren, {SDL_Texture *&texture, const char *imagePath} ... ){
for(int i = 0; i < numOfPairs; i++){
SDL_Surface *curImage = IMG_Load(pairs[i].second);
pairs[i].first = SDL_CreateTextureFromSurface(ren, curImage);
SDL_FreeSurface(curImage);
}
}
Where I have a variable number of pairs and each pair contains a texture and its correspondent path. I've no idea, which way would be best to approach this problem. I've thought about using the <cstdarg> library's variadic functions but I read on another question that that's not a good solution.
the way that immediately comes to mind is std::vector. You could pass a vector of std::pair or of std::tuple if you are using a c++11 or better compiler.
very simple to do
#include <vector>
#include <tuple>
....
std::vector<std::tuple<SDL_texture, const char *>> args;
args.push_back(std::make_tuple(texture1, path1));
args.push_back(std::make_tuple(texture2, path2));
then your func
void load_Image(SDL_renedred *ren, const std::vector<std::tuple<SDL_texture, const char *>> &args)
{
std::tuple<SDL_textture, const char*> &arg1 = args[0];
// or if you have modern c++
auto &arg1 = args[0];
}
(not compiled, probably got typos in it.)
Although I hate it, you can use std::initializer_list like:
#include <initializer_list>
#include <tuple>
void loadImage(SDL_Renderer *ren, std::initializer_list<std::tuple<SDL_Texture*&,const char *&>> pair_list ){
for(auto p:pairlist){//initializer_list cannot be indexed but only iterated
SDL_Surface *curImage = IMG_Load(p.second);
p.first = SDL_CreateTextureFromSurface(ren, curImage);
SDL_FreeSurface(curImage);
};
};
//call site:
loadImage(ren,{tie(tex1,path1),tie(tex2,path2),tie(tex3,path3)});
It is recommended to store your pointers in std::unique_ptr instants with costume deleter. And I guess you'd better change your data structue design to avoid tying objects like that - e.g. using a std::map:
#include <initializer_list>
#include <memory>
#include <map>
struct MySDLDeleter{
void operator(SDL_Texture* texPtr){SDL_FreeTexture(texPtr);};
void operator(SDL_Renderer * renPtr){SDL_FreeRenderer(renPtr);};
void operator(SDL_Surface * srfPtr){SDL_FreeSurface(srfPtr);};
};
auto loadImage(std::unique_ptr<SDL_Renderer,MySDLDeleter> ren, std::initializer_list<const char *> path_list ){
std::map<const char *,std::unique_ptr<SDL_Texture,MySDLDeleter> texMap;
for(auto p:path_list ){
std::unique_ptr<SDL_Surface ,MySDLDeleter> curImage = IMG_Load(p.second);
texMap.insert(p,SDL_CreateTextureFromSurface(ren.get(), curImage.get()));
};
return texMap;
};
//call site:
auto texMap=loadImage(create_the_renderer_ptr(),{path1,path2,path3});
First of all write a function that will process each pair (i.e. what you have inside your for loop):
using ImagePair = std::pair<SDL_Texture*&, const char*>;
void processImage(ImagePair imgPair)
{
SDL_Surface *curImage = IMG_Load(imgPair.second);
imgPair.first = SDL_CreateTextureFromSurface(ren, curImage);
SDL_FreeSurface(curImage);
}
Then if you have C++11 or above, you can use a brace-initialization trick to call processImage() for each argument:
template <typename ... Ts>
void loadImage(Ts ... ts)
{
using dummy = int[];
(void)dummy {0, (processImage(ts)), 0)... };
}
What you're doing here is taking advantage of the fact that the compiler knows it has to do a pack expansion inside a brace-initialization list. That way you can avoid having to write recursive variadic template functions yourself.
Here you are building a dummy array of integers, which is equal in size to the number of variadic arguments you pass in. For each argument you call the function processImage(), but using the comma operator you set the value in the array to 0. So you expand the pack and call processImage() for each argument while creating a dummy array. This answer might explain it more clearly.
If you have C++17 or above, you can simplify further and use a fold expression:
template<typename... Ts>
void loadImage(Ts... args)
{
(processImage(args),...);
}
I was reviewing some older code of mine and I saw the code using pointers to implement a tree of Variant objects. It is a tree because each Variant can contain an unordered_map of Variant*.
I looked at the code and wondered why isn't it just using values, a std::vector<Variant>, and std::unordered_map<std::string, Variant>, instead of Variant*.
So I went ahead and changed it. It seemed okay except one thing, I got errors:
/usr/local/include/c++/6.1.0/bits/stl_pair.h:153:11: error: 'std::pair<_T1, _T2>::second' has incomplete type
_T2 second; /// #c second is a copy of the second object
^~~~~~ main.cpp:11:8: note: forward declaration of 'struct Variant'
struct Variant
^~~~~~~
So I figured I could trick the compiler into delaying the need to know that type, which didn't work either.
Working Not Working! (MCVE)
I thought this worked earlier but it actually doesn't, I forgot ::type on the using HideMap...
#include <vector>
#include <unordered_map>
#include <iostream>
template<typename K, typename V>
struct HideMap
{
using type = std::unordered_map<K, V>;
};
struct Variant
{
using array_container = std::vector<Variant>;
// Does not work either
using object_container = typename HideMap<std::string, Variant>::type;
// Fails
//using object_container = std::unordered_map<std::string, Variant>;
private:
union Union
{
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
Union data;
bool weak;
};
int main()
{
Variant v;
std::cout << "Works" << std::endl;
}
So, my question is, why does it work okay for vector and not unordered_map?
If the problem is the inability to use incomplete types, is there a way to delay the instantiation of the unordered_map? I really don't want every object property to be a separate new allocation.
This uses placement new to defer the initialization of the Union to the constructor where Variant is a complete type. You need to reinterpret_cast everywhere you need to use the Union. I made an effort to not have any strict-alignment violations.
#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
struct Variant {
Variant();
~Variant();
private:
std::aligned_union<0, std::vector<Variant>,
std::unordered_map<std::string, void *>,
std::int64_t>::type data;
};
namespace Variant_detail {
using array_container = std::vector<Variant>;
using object_container = std::unordered_map<std::string, Variant>;
union Union {
std::int64_t vint;
array_container varr;
object_container vobj;
// These are required when there are union
// members that need construct/destruct
Union() {}
~Union() {}
};
}
Variant::Variant() {
//make sure that std::unordered_map<std::string, Variant> is not too large
static_assert(sizeof(std::unordered_map<std::string, Variant>) <=
sizeof data, "Variant map too big");
static_assert(alignof(std::unordered_map<std::string, Variant>) <=
alignof(decltype(data)), "Variant map has too high alignment");
auto &my_union = *new (&data) Variant_detail::Union;
my_union.vint = 42;
}
Variant::~Variant() {
reinterpret_cast<Variant_detail::Union &>(data).~Union();
}
int main() {
Variant v;
std::cout << "Works" << std::endl;
}
I am working on implementing a generic stack data strucuture using STL and boost library.
#include <iostream>
#include <cstdio>
#include <stack>
#include <boost/any.hpp>
#include <boost/type_index.hpp>
using namespace std;
class Stack{
private:
std::stack<boost::any> st;
public:
bool empty();
int size();
boost::any top();
void push(boost::any ele);
void pop();
};
bool Stack::empty(){
return st.empty();
}
int Stack::size(){
return st.size();
}
boost::any Stack::top(){
return st.top();
}
void Stack::push(boost::any e){
st.push(e);
}
void Stack::pop(){
st.pop();
}
int main(){
Stack st;
int a = 10;
st.push(a);
int b = boost::any_cast<int>(st.top());
float c = 10.0;
st.push(c);
}
Although it's working perfectly but I want to avoid explicit typecast while retrieving an item from the stack. I want that somehow stack should return item after typecasting it automatically based on the item's type.
I am planning to maintain a hashmap with the stack which could store type information of every element and could be used to type cast each item before returning it, but I am not able to write this as code. Please suggest me some possible ways.
You cannot automatically cast to the right type; then the return type of your top() function would depend on whatever happens at runtime. So, what return type would you give your top() function at compile time? The best you can do is something like
template <typename T>
T top()
{
return boost::any_cast<T>(stack.top());
}
Edit: As for your comment – no, you cannot use auto return type to get the behavior you hope, because the compiler will deduce what type auto represents at compile time – and it deduces what you return: a boost::any. Anything more specific can only be known at runtime.
I have an issue in assigning value to a object.
my object definition says:
class myobject {
public:
var_type type;
union value_type value;
myobject(int value);
myobject(string value);
...
};
enum var_type {
var_int,
var_str,
var_float
};
union value_type {
int;
real;
string;
};
myobject* object = get_object("name");
//here i need to change its value, i dont have any setvalue function.
Now in some other file i need to update the value of myobject, but i dont know the value type. say initial value_type is int, and my function assigns it a string, i get absurd value at doign GetValue().
what should be more efficient way to get the value type of the object, change my string value to the old value type it supporting and modified it. I cant change in the definition class of myobject.
Thanks
Ruchi
With limited information provided in your question I assume that you want to change the value of your pointer "object" depending on input which could string or int or something else.
Check this program, I make use of "boost::any" and typeid. Review this option and test it in your program. Else do explicitly explain with some code example what you want to achieve.
Also union with string would give you compile problems? Is it not?
#include <iostream>
#include <string>
#include <typeinfo>
#include <boost/any.hpp>
#include <boost/unordered_map.hpp>
#include<list>
using namespace std;
class myobject {
public:
myobject(int value)
{cout<<"int ctr"<<endl;}
myobject(std::string value)
{cout<<"string ctr"<<endl;}
};
int main()
{
list<boost::any> valueType;
std::string valStr("name");
valueType.push_back(valStr);
int num = 10;
valueType.push_back(num);
myobject* object = NULL;
for(list<boost::any>::iterator itr = valueType.begin();
itr != valueType.end();
++itr)
{
if((*itr).type() == typeid(std::string))
object = new myobject((boost::any_cast<std::string>(*itr)));
else if((*itr).type() == typeid(int))
object = new myobject((boost::any_cast<int>(*itr)));
}
return 0;
}
In my programming class we're just being introduced to the concept of templates within C++. This is a concept we never covered in my class on Java last semester, and the whole syntax of C++ is really throwing me for a loop. I'm getting a long string of compilation errors with the code I will post below. It would make me think that I'm missing something very obvious within the template Syntax. The following is just an example template I'm trying to work with, something to get me started on the homework. If any of you have any insights as to why this isn't compiling, I'd be grateful. Thanks!!
keyValuePair.h
#include <fstream>
#include <iostream>
#include <string>
#ifndef KEYVALUEPAIR
#define KEYVALUEPAIR
template<class key, class value>
class keyValuePair
{
private:
key kvar;
value vvar;
public:
keyValuePair(); //Default Constructor
void setKvar(key object1); //Method to set kvar to a value
void setVvar(value object2); //Method to set vvar to a value
key getKvar(); //Method to return kvar
value getVvar(); //Method to return vvar
};
#include "keyValuePair.cpp"
#endif
keyValuePair.cpp
#include <iostream>
#include <fstream>
#include <string>
#include "keyValuePair.h"
template<class key, class value>;
keyValuePair<key, value>::keyValuePair()
{
}
template<class key, class value>; //return the value of kvar
key keyValuePair<key, value>::getKvar()
{
return kvar;
}
template<class key, class value>; //return the value of vvar
value keyValuePair<key, value>::getVvar()
{
return vvar;
}
template<class key, class value>; //set the value of kvar
void keyValuePair<key, value>::setKvar(key& object1)
{
object1 = kvar;
}
template<class key, class value>; //set the value of vvar
void keyValuePair<key, value>::setVvar(value& object2)
{
object2 = vvar;
}
main.cpp
#include <fstream>
#include <iostream>
#include <string>
#include "keyValuePair.h"
using namespace std;
int main(int argc, char* argv[])
{
fstream myFile(argv[1], ios::in);
fstream fout("out.txt", ios::out);
myFile.close();
fout.close();
keyValuePair<string, int> sample;
sample.setKvar("Hello World.");
sample.setVvar(3);
cout << sample.getKvar() << sample.getVvar() << "\n";
return 0;
}
Remove the semicolon after template<class key, class value>:
!--here
template<class key, class value>;
keyValuePair<key, value>::keyValuePair()
{
}
You have several small mistakes in the syntax.
you declared setKvar and setVvar to take the parameter by value, but defined them to take a reference. (Drop the & in .cpp file)
Do not put a semicolon after template<class key, class value>
in setKvar and setVvar, you have the argumets swapped in the assignment. It should read like kvar = object1; in setKvar and analogically vvar = object2; in setVvar
Do not include the cpp file in the header, include the content directly into the header file, like PorkyBrain said.
keyValuePair.h should not include keyValuePair.cpp. Also the function bodies in keyValuePair.cpp should be declaired directly (different best practaces for templates than normal functions)
template<class key, class value>
class keyValuePair
{
private:
key kvar;
value vvar;
public:
keyValuePair(){} //Default Constructor
void setKvar(key object1){kvar = object1;} //Method to set kvar to a value
void setVvar(value object2){vvar = object2;} //Method to set vvar to a value
key getKvar(){return kvar;} //Method to return kvar
value getVvar(){return vvar;} //Method to return vvar
};
The semicolons after the
template<class key, class value>;
are a typo too.
Also your setKvar function assigns the value of kvar to the parameter taken by reference. I don't this this is what you want seeing as the function is named set.
The reason the bodies of template class member functions are usually declared in line is that the compiler will only generate code for a particular type or types (which is called instantiating the template for the particular type) if it sees them being used in that compilation unit (usually a compilation unit and a .cpp file are the same thing).
This means that if you put the function bodies in keyValuePair.cpp and try to use them in main.cpp the linker will give you "not found" errors because in the compilation unit keyValuePair.cpp the compiler could not see them being used so it never created them.
You can cause the template to be instantiated for specific types directly like this:
template keyValuePair<int,long>;
however this is probably bad style because every time you want to use your template with new types you need to add these declarations to your keyValuePair.cpp file which defeats the purpose of having the flexibility in the first place.