By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
426,012 Members | 988 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 426,012 IT Pros & Developers. It's quick & easy.

How do I make my convert() function do nothing for equal types?

P: n/a
Hello, I've made a templated class Option (a child of the abstract base
class OptionBase) that stores an option name (in the form someoption=) and
the value belonging to that option. The value is of the type the object is
instantiated with. In my test program I have Option<std::string> and
Option<long>. Here's the code for OptionBase and Option along with a small
helper function. In the code are comments describing my problem, look
closely at the read_option() and convert() functions in the Option class.

#ifndef OPTION_HPP
#define OPTION_HPP

#include <stdexcept>
#include <string>
#include <typeinfo>

static bool
starts_with(const std::string& s, const std::string& starts_with)
{
if(s.length() < starts_with.length())
return false;

std::string str = s.substr(0, starts_with.length());

if(str == starts_with)
return true;

return false;
}

class OptionBase
{
public:
OptionBase(const std::string& name)
:
m_name(name),
m_not_set(true) {}

virtual ~OptionBase() {}

virtual void read_option(const std::string&) = 0;

const std::string get_name() const
{
return m_name;
}

protected:
std::string m_name;
bool m_not_set;
};

template<typename T>
class Option : public OptionBase
{
public:
Option(const std::string& name)
:
OptionBase(name) {}

virtual void read_option(const std::string& s)
{
if(!starts_with(s, m_name))
throw std::runtime_error(std::string("Didn't find option ") +
m_name);

std::string str = s.substr(m_name.length(), s.length());

if(str.empty())
throw std::runtime_error("Option lacks value.");

/* Problem: Will try to convert std::string to std::string
which will lead to "Iron Gual Dye" becoming just "Iron". */
T tmp = convert(str);

set_value(tmp);
}

T get_value() const
{
if(m_not_set)
throw std::runtime_error("Called get_value() when no value had been
set.");

return m_value;
}

void set_value(const T& value)
{
m_value = value;
m_not_set = false;
}

private:
T convert(const std::string& s)
{
/* Here I want to simply return s if(typeid(T) == typeid(std::string)
but return (T)s doesn't compile when this class is instantiated
with type long (I'm using long and std::string in my test program).
*/

stringstream ss;
ss << s;

T out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

T m_value;
};

#endif /* #ifndef OPTION_HPP */

So the problem is convert(). When I have instantiated my object with
std::string and I call read_option() on that object it will call convert()
and convert() will convert a string containing spaces to a substring up to
the first space. Iron Gual Dye becomes Iron for example. How should I
prevent this from happening? If I have instantiated with std::string I don't
want to call convert (because it messes up strings with spaces) but I have
to because of set_value().

Hope you understand what I mean...I can provide a complete and compilable
example exhibiting the problem should anyone want me to.

/ Eric
Jul 23 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a

Eric Lilja wrote:
template<typename T>
class Option : public OptionBase
{
public:
Option(const std::string& name)
:
OptionBase(name) {}

virtual void read_option(const std::string& s)
{

[snip]

/* Problem: Will try to convert std::string to std::string
which will lead to "Iron Gual Dye" becoming just "Iron". */
T tmp = convert(str);

set_value(tmp);
}

[snip]
private:
T convert(const std::string& s)
{
/* Here I want to simply return s if(typeid(T) == typeid(std::string) but return (T)s doesn't compile when this class is instantiated with type long (I'm using long and std::string in my test program). */

stringstream ss;
ss << s;

T out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

T m_value;
};

#endif /* #ifndef OPTION_HPP */

So the problem is convert(). When I have instantiated my object with
std::string and I call read_option() on that object it will call convert() and convert() will convert a string containing spaces to a substring up to the first space. Iron Gual Dye becomes Iron for example. How should I prevent this from happening? If I have instantiated with std::string I don't want to call convert (because it messes up strings with spaces) but I have to because of set_value().

Hope you understand what I mean...I can provide a complete and compilable example exhibiting the problem should anyone want me to.

/ Eric

You can create a specialization for Option<std::string> that does not
read from the string stream.

Hope this helps,
-shez-

Jul 23 '05 #2

P: n/a

"Shezan Baig" wrote:
Eric Lilja wrote:
template<typename T>
class Option : public OptionBase
{
public:
Option(const std::string& name)
:
OptionBase(name) {}

virtual void read_option(const std::string& s)
{

[snip]

/* Problem: Will try to convert std::string to std::string
which will lead to "Iron Gual Dye" becoming just "Iron". */
T tmp = convert(str);

set_value(tmp);
}


[snip]
private:
T convert(const std::string& s)
{
/* Here I want to simply return s if(typeid(T) ==

typeid(std::string)
but return (T)s doesn't compile when this class is

instantiated
with type long (I'm using long and std::string in my test

program).
*/

stringstream ss;
ss << s;

T out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

T m_value;
};

#endif /* #ifndef OPTION_HPP */

So the problem is convert(). When I have instantiated my object with
std::string and I call read_option() on that object it will call

convert()
and convert() will convert a string containing spaces to a substring

up to
the first space. Iron Gual Dye becomes Iron for example. How should I

prevent this from happening? If I have instantiated with std::string

I don't
want to call convert (because it messes up strings with spaces) but I

have
to because of set_value().

Hope you understand what I mean...I can provide a complete and

compilable
example exhibiting the problem should anyone want me to.

/ Eric

You can create a specialization for Option<std::string> that does not
read from the string stream.

Hope this helps,
-shez-


Thanks for your reply. I tried moving the convert() function outside the
class and made a specialization for it for std::string but it always calls
the "wrong" convert. The code:
template<typename T>
T convert(const std::string& s, T)
{
stringstream ss;
ss << s;

T out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

template<typename T>
std::string convert(const std::string& s, std::string)
{
return s;
}

But maybe that's not what you meant? My template skills are a bit weak I
must say =/

/ Eric
Jul 23 '05 #3

P: n/a

"Eric Lilja" wrote:

"Shezan Baig" wrote:
Eric Lilja wrote:
template<typename T>
class Option : public OptionBase
{
public:
Option(const std::string& name)
:
OptionBase(name) {}

virtual void read_option(const std::string& s)
{

[snip]

/* Problem: Will try to convert std::string to std::string
which will lead to "Iron Gual Dye" becoming just "Iron". */
T tmp = convert(str);

set_value(tmp);
}


[snip]
private:
T convert(const std::string& s)
{
/* Here I want to simply return s if(typeid(T) ==

typeid(std::string)
but return (T)s doesn't compile when this class is

instantiated
with type long (I'm using long and std::string in my test

program).
*/

stringstream ss;
ss << s;

T out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

T m_value;
};

#endif /* #ifndef OPTION_HPP */

So the problem is convert(). When I have instantiated my object with
std::string and I call read_option() on that object it will call

convert()
and convert() will convert a string containing spaces to a substring

up to
the first space. Iron Gual Dye becomes Iron for example. How should I

prevent this from happening? If I have instantiated with std::string

I don't
want to call convert (because it messes up strings with spaces) but I

have
to because of set_value().

Hope you understand what I mean...I can provide a complete and

compilable
example exhibiting the problem should anyone want me to.

/ Eric

You can create a specialization for Option<std::string> that does not
read from the string stream.

Hope this helps,
-shez-


Thanks for your reply. I tried moving the convert() function outside the
class and made a specialization for it for std::string but it always calls
the "wrong" convert. The code:
template<typename T>
T convert(const std::string& s, T)
{
stringstream ss;
ss << s;

T out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

template<typename T>
std::string convert(const std::string& s, std::string)
{
return s;
}

But maybe that's not what you meant? My template skills are a bit weak I
must say =/

/ Eric


I solved it, here it is with the convert() function as a stand-alone
function:
template<typename T1, typename T2>
T2 convert(const T1& a, const T2&)
{
stringstream ss;
ss << a;

T2 out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

template<>
std::string convert(const std::string& s, const std::string&)
{
return s;
}

Now, should I (can I?) make convert a member of the class Option? And can I
loose the second argument (it's after all not used in the function)?

/ Eric
Jul 23 '05 #4

P: n/a
Eric Lilja wrote:
I solved it, here it is with the convert() function as a stand-alone
function:
template<typename T1, typename T2>
T2 convert(const T1& a, const T2&)
{
stringstream ss;
ss << a;

T2 out;

if(!(ss >> out))
throw runtime_error("Conversion not possible.");

return out;
}

template<>
std::string convert(const std::string& s, const std::string&)
{
return s;
}

Now, should I (can I?) make convert a member of the class Option? And can I loose the second argument (it's after all not used in the function)?

/ Eric

You don't need to second argument. In the option class, declare it
like this:

template<typename RETURN_TYPE>
RETURN_TYPE convert(const std::string& s);

Outside the class, provide two definitions for this function, one
generic and the other specialized for std::string:

template <typename TYPE>
template <typename RETURN_TYPE>
RETURN_TYPE Option<TYPE>::convert(const std::string& s)
{
// ...
}

template <typename TYPE>
template <>
std::string Option<TYPE>::convert<std::string>(const std::string& s)
{
// ...
}
When you call the convert function, you call it like this:

convert<TYPE>(s);

So, if 'TYPE' is 'std::string', it will call the specialised version.

Hope this helps,
-shez-

Jul 23 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.