Re: Mapping a non-const integral to a type Organization: ...
Marcos Bento wrote:
I'm having a bit of a problem with the mapping a non-const integral to
a type. The code below shows my predicament:
int main()
{
Types user_choice = typeX; // Actually, this is taken from
configuration file - so non-constant integral!
const char *file = "input.txt";
switch( user_choice ) {
case typeX: {
X input;
::read(input, file);
}
I understand that the scope of the 'input' variable is only the case
block, but how can I take the variable input out of such block, based
on the value of user_choice (without changing X, Y, Z, and functions f
or read - these represent library defined types)?
I though of using template <typename T> struct Wrapper, and then use
Wrapper<X>, Wrapper<Y>, ... but I can't make it work based on the non-
constant enum value.
I think that you may want to take a look at Boost Variant.
If you want some sort of Wrapper, I'm not sure if this will work for you
or not, more of a point of departure than a solution. I think it has
some problems in that it won't be very efficient. If your X, Y, Z
classes are large this will have some serious drawbacks.
I think this may be similar to an Abstract Factory. I would be grateful
if someone can tell me the name of this pattern.
#include <iostream>
#include <string>
typedef enum { typeX, typeY, typeZ } Types;
class X {};
class Y {};
class Z {};
// we add an invalid class so we always have
// something to point to in Wrapper below
class Invalid {};
// WrapperBase and WrapperType<>, below,
// need an interface that is appropriate
// for X, Y and Z.
//
class WrapperBase {
public:
virtual ~WrapperBase() {}
virtual std::string name() const = 0;
virtual WrapperBase *clone() const = 0;
};
template<typename T>
class WrapperType : public WrapperBase {
T t_;
public:
WrapperType() : t_() {}
WrapperType(const T &t) : t_(t) {}
T &t() { return t_; }
std::string name() const;
WrapperType *clone() const { return new WrapperType(t_); }
};
// specialize name for each of the
// classes we want to make, including
// WrapperType<Invalid>
template<>
std::string WrapperType<X>::name() const { return "X"; }
//
template<>
std::string WrapperType<Y>::name() const { return "Y"; }
//
template<>
std::string WrapperType<Z>::name() const { return "Z"; }
//
template<>
std::string WrapperType<Invalid>::name() const { return "Invalid"; }
// Wrapper is a little bit like a container class,
// but points to the WrapperType<> classes.
// It also needs an interface that is suitable
// for X, Y and Z. Although I suppose you
// could expose the pointer to WrapperBase.
class Wrapper {
WrapperBase *p_; // might be better to use a smart pointer
static Wrapper factory(const Types &t) {
// here's our factory to make
// a new Wrapper based on a value
// of Types
if(t == typeX) return WrapperType<X>();
if(t == typeY) return WrapperType<Y>();
if(t == typeZ) return WrapperType<Z>();
return WrapperType<Invalid>();
}
public:
void swap(Wrapper &w) {
std::swap(p_,w.p_);
}
Wrapper() : p_(new WrapperType<Invalid>() ) {}
Wrapper(const Wrapper &w) : p_(w.p_->clone()) {}
template<typename T>
Wrapper(const WrapperType<T> &w) : p_(w.clone()) {}
Wrapper(const Types t) : p_( factory(t).p_->clone() ) {}
~Wrapper() { delete p_; } // better to use some smart pointer
//
Wrapper &operator=(const Wrapper &w) {
Wrapper temp(w);
swap(temp);
return *this;
}
std::string name() const { return p_->name(); }
};
// now we only need one f function
// instead of three
void f(const Wrapper &w) { std::cout << w.name() << std::endl; }
int main() {
// it should be easy enough to use
// a Types variable as the argument
// to w's ctor
const Wrapper w(typeY);
f(w);
}
LR
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]