Haven't you just reinvented boost::any?
Printable View
Haven't you just reinvented boost::any?
i wouldn't know because i haven't used it, however, i sincerely doubt it because if that's all there is to it then i am underwhelmed by that particular library's cleverness. i take it then, if you think that is analogous to boost::any, that you don't consider that 'wrong'?
Nope, neither your example nor boost::any is wrong, but I don't think it can be as useful in this case, because you need to know the type you are getting, or you get a compile error.
well then clearly that's a design problem ;)
I dunno. Scripting clearly requires some flexible system that needs to work without knowing the exact type.
I wouldn't know how to implement a system to make such a thing work.
Well I just read through all the post and I will take some time to think re-think my design as a whole. I actually might explore the option of dynamically allocating memory. Though I tend to want to stay away from it do to the complexity it adds. Maybe something along the lines of
Also for info sakes my script would no more complicated then the below example.Code:class Variable
{
public:
Variable();
~Variable();
void AddScriptVariable( const std::string buffer );
void AddScratchVariable( const std::string name, char type, void *value );
char GetType();
std::string GetName();
void *GetData();
private:
char m_type; // Type of data stored in the variable.
std::string m_name; // Name of the variable.
void *m_data; // Data stored in the variable.
};
#begin
btest bool true
ftest float 27.3978
stest string "WEeeeeEEE"
#end
Variable name, then type, then value.
Regards
Chad
one might:
or something to that effect.Code:class abstractFunctor
{
public:
virtual void exec()=0;
};
template<typename input,typename output> class concreteFunctor : public abstractFunctor
{
protected:
input& i;
output& o;
typedef output (*pfunc)(input);
pfunc func;
public:
concreteFunctor (input& _i,output& _o,pfunc _func):
i(_i),
o(_o)
{
}
void exec()
{
o = func(i);
}
};
Yes, maybe. You might need to hide virtual functions that relies on template types in the parameter list, perhaps through extra abstraction and more generic (simple functions like your exec) functions.
Maybe we should just give up and use Boost.Python. Python already has a list type that does not need to be homogeneous, Boost.Python emulates it.
The purpose of a template class is the generation of classes. If the OP needs a stable interface to several mechanically related classes, a template class is exactly what he needs to do the implementation.Quote:
If you want or [...] the purpose of a template class.
O_oQuote:
[...]class Variable[...]
You can do a lot with templates, but if you are going to do anything with these types, you'll eventually have to do the work.
If you don't want to do the work, or don't feel capable, you'll have to find an existing scripting library. (whiteflags provided a nice one.)
That said, templates will let you serialize and store the types safely and C++ already tracks the types of things if you let it. I'll give you a simple example. (Which is not up to my usual standard--example memory leaks.)
Soma
Code:#include <iostream>
#include <iterator>
#include <map>
#include <sstream>
#include <stdexcept>
#include <string>
#include <typeinfo>
using namespace std;
struct variable_interface
{
virtual string get() const = 0;
virtual void set
(
const string & f
) = 0;
virtual istream & in
(
istream & f
) = 0;
virtual ostream & out
(
ostream & f
) const = 0;
virtual const type_info & type() const = 0;
};
template
<
typename type_F
>
struct variable: variable_interface
{
virtual string get() const
{
ostringstream v;
v << m;
return(v.str());
}
virtual void set
(
const string & f
)
{
istringstream v(f);
v.setf(ios::boolalpha);
type_F t;
if(!(v >> t))
{
throw(runtime_error("bad input"));
}
swap(m, t);
}
virtual istream & in
(
istream & f
)
{
return(f);
}
virtual ostream & out
(
ostream & f
) const
{
cout << m;
return(f);
}
virtual const type_info & type() const
{
return(typeid(type_F));
}
type_F m;
};
template <> struct variable<string>: variable_interface
{
virtual string get() const
{
ostringstream v;
v << m;
return(v.str());
}
virtual void set
(
const string & f
)
{
istringstream v(f);
string t;
if(!(getline(v, t)))
{
throw(runtime_error("bad input"));
}
swap(m, t);
}
virtual istream & in
(
istream & f
)
{
return(f);
}
virtual ostream & out
(
ostream & f
) const
{
cout << m;
return(f);
}
virtual const type_info & type() const
{
return(typeid(string));
}
string m;
};
istream & operator >>
(
istream & lhs_f,
variable_interface & rhs_f
)
{
return(rhs_f.in(lhs_f));
}
ostream & operator <<
(
ostream & lhs_f,
variable_interface & rhs_f
)
{
return(rhs_f.out(lhs_f));
}
int main()
{
string input;
map<string, variable_interface *> state;
while(getline(cin, input))
{
istringstream v(input);
string name;
string type;
string value;
v >> name;
v >> type;
getline(v, value);
if("bool" == type)
{
state[name] = new variable<bool>;
}
else if("float" == type)
{
state[name] = new variable<float>;
}
else if("string" == type)
{
state[name] = new variable<string>;
}
else
{
throw(runtime_error("bad input"));
}
state[name]->set(value);
}
const map<string, variable_interface *>::const_iterator begin(state.begin());
const map<string, variable_interface *>::const_iterator end(state.end());
for(map<string, variable_interface *>::const_iterator cursor(begin); end != cursor; ++cursor)
{
cout.setf(ios::boolalpha);
cout << cursor->first;
if(typeid(bool) == cursor->second->type())
{
cout << " as bool ";
}
else if(typeid(float) == cursor->second->type())
{
cout << " as float ";
}
else if(typeid(string) == cursor->second->type())
{
cout << " as string ";
}
else
{
cout << " as <unknown> ";
}
cout << *(cursor->second) << '\n';
}
return(0);
}