Re: Why is 'Variant' used in so many contexts?
On Jul 20, 12:51 am, Eugene Gershnik <gersh...@hotmail.com> wrote:
Another common usage [of variants] is when you have an
external data source (like database, XML file etc.).
You usually know the set of possible types you can read
from them but you may not know the exact type of the
next item.
This second usage is a key observation that's been only minimally
explained and explored in this thread.
Any program that needs to handle data of a type that won't be known
until run-time might reasonably consider using variants. Such
programs include language interpreters, database implementations,
database-tools that need to read metadata and work on arbitrary tables
that may have been defined after the tool was written.
To understand why variants are useful, ask yourself how you would
write an interpreter to read a script containing "string s; int i;" or
similar. You'd probably want to create a hash/binary-map from
identifiers "s", "i" to the variables, but they are of differing
types. You then end up choosing between:
1) iterating over a map per type, and handling them all differently in
high-level code
2) having one map, but to something that might contain a string or an
int, e.g.
a) store ints in strings? very inefficient!
for binary '+', need a bool to say it's an int
so you can choose between string concatenation and
integer addition
b) generalise the above into an enum for type and
a union
c) use a base class with derived String and Int
classes
Option b) is similar to the boost variant, and contrasted with c) in
the post by Jiri Palecek.
There are also a few variations on the "variant" concept though, known
by various often-conflicting names in different systems:
1) the discriminated union idea, e.g. enum { STRING, INT }
type_stored_; union { std::string* p_string_; int int_; } };
2) a class with a templated constructor/operator=, storing data of an
arbitrary type and keeping RTTI type information (IIRC only guaranteed
to be available for classes using virtual inheritance) for use by
later queries and accessors
3) a class with templated constructor/operator=, that uses the value-
to-store argument to instantiate a template with a non-templated base
class that allows a set of common operations over the stored data
(e.g. instantiating conversion to string via operator<<, or preserving
maths functionality by intantiating operator+ |-|*|/)
All have strengths and weaknesses: 1) works well but only for the
predefined types, 2) requires RTTI and the user may need to implement
the switching thereon, 3) works for any type that can be instantiated
for the set of required operations, but other functionality offered by
only some of the types may be hard to preserve.
There are also considerations re compilation firewalls and locality of
code. For example, option 3) requires a templated "variant" type, but
the base class through which the data is handled is of some known
type, so the user can write code to work on this base class that does
not itself need to be templated. Any new types that can be
instantiated can be handled without changes to or recompilation of the
"client" code. This kind of analysis can be preformed for all the
different options....
HTH
Cheers,
Tony
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]