Hey guys,

Could I "teach" my compiler to do automatic type conversions for me?

So when I have this program:

#include <cstdio>
#include <string>
using std::string;

int main(){
    int x;
    string y = "1234567890";

    x = y;

    printf("y: %s == %d\n", y.c_str(), x);

    return 0;
}

It won't give me main.cpp|10|error: cannot convert `std::string' to `int' in assignment| But compile and do everything alright? I know C++ has this function somewhere since it can do a lot of conversions without having to use functions on the line itself (i.e. by simply casting), but I couldn't find details about it.

Thanks in advance,

There are several ways to do it. One way is to use c++ stringstream class. And don't use printf() in c++ programs, it will work, but iostream is more suited to c++.

#include <sstring> // stringstream class

int main()
{
    int x;
    string y = "1234567890";
    stringstream str(y);
    str >> x;
   cout << x << "\n";
}

It seems you like adventures:

struct Int 
{
    Int(int n = 0):value(n){}
    operator int&() { return value; }
    operator const int&() const { return value; }
    Int& operator=(const char* p) {
        value = (p?atoi(p):0);
        return *this;
    }
    Int& operator=(const std::string& s) {
        *this = s.c_str();
        return *this;
    }
    int value;
};

int main()
{
    Int foo;
    foo = "123";
    cout << foo << endl;
    std::string s("2009");
    foo = s;
    cout << foo << endl;
    foo += 1;
    cout << foo << endl;
    int k;
    k = foo = 1000;
    cout << foo << '\t' << k << endl;
    return 0;
}

It seems you like adventures:

The rabbit hole can get deeper :)

template<typename T>
T 
convert(const std::string& SRef)
{
  T x;
  std::istringstream ostr(SRef);
  ostr>>x;
  return x;
}

template<typename T>
struct Type
{
    Type() {}  // THIS DOES not set types that don't have default constructor
    Type(T n):value(n){}
    operator T&() { return value; }
    operator const T&() const { return value; }
    Type& operator=(const char* p) 
      {
        value = convert<T>(std::string(p));
        return *this;
     }
    Type& operator=(const std::string& s) 
      {
        *this = convert<T>(s);
        return *this;
    }
    T value;
};

int main()
{
  Type<int> foo;
  Type<double> dfoo;
  foo = "123";
  dfoo="3.141";
  std::cout << foo <<" "<<dfoo<< std::endl;
  std::string s("2009");
  foo = s;
  std::cout << foo << std::endl;
  foo += 1;
  std::cout << foo << std::endl;
  int k;
  k = foo = 1000;
  std::cout << foo << '\t' << k << std::endl;
  return 0;
}

Note that I have used Ancient Dragon's convert function (For real code please add some checks!!!)

In short this post shows how templates can be your best friend (and your worst enemy).

EDIT: Removed the first paragraph, made no sense.

Major thanks for that streamstring thingy, ton of opportunities.

Edit: WHOA! Didn't refresh for an hour (due to telephone) then posted a reply, heh. Thanks for all the input, I think I can make something of that.

Small new unrelated question:

Do you guys think macros such as these are okay to use, or do you have an alternative or something?

#define setElementMember(x) {\
    if(attrName == "x"){\
        str >> this->x;\
    }\
}

That's one way to put it, how would I do that? I need to make a string at compile time you see: this->x; refers to a member with the name x.

For instance, element has a member name, so now I can say: setElementMember(name) And it'll set the member variable and compare with the correct string. I think the only way to do this is with macros, but I wasn't sure.

First of all, if I'm not mistaken, your macro is wrong: the string "x" will not get replaced. You need to use some weird escaping thing to concatenate strings or something, like "##x##" . Maybe your version is fine; I don't know.

Second, the macro is incorrectly named, and it's named like a function would be named. A more reasonable name would be something like CRAZY_UNSAFE_DANGER_DANGER_SET_MEMBER_IF_attrName_EQUALS_TOKEN(name)

Second, I see no reason to believe this claim:

I need to make a string at compile time you see:

We can't actually discuss avoiding this macro without discussing what caused you want to use this preprocessing directive.

I changed it to #x and it works fine. Besides your needless ranting you haven't really said anything I asked for like an alternative.

And why would I make a "claim" about such a thing? I have class (element) with a private member (int name), is that weird or something?

There's a bit of a nasty trick you can perform with arrays and references which can mimic the effect of modifying different data members of a class/struct at runtime.

Given a simple struct like the following

struct person
{
    std::string forename;
    std::string surname;
    std::string telephone;
    std::string postcode;
};

Here, there's no safe nor portable way to maintain the names in the struct as well as being able to switch between them at compile time

One possible way around this is to stick all the data members in an array

struct person
{
    std::string vars[4];
};

but that loses the nice, comfortable member names which are important for readability.

A common solution in C is to use an enum to index different members in a struct, but this is hardly elegant

struct person
{
    std::string vars[4];
}; 

enum { forename , surname , telephone , postcode }; 

void func()
{
    person my_person;
    my_person.vars[forename] = "John";
}

A cleaner solution is to assign references to each position in the array. which makes the existence of the array all but invisible, except for those situations when you need to switch between data members at runtime

struct person
{
    std::string vars[4];
    std::string& forename;
    std::string& surname;
    std::string& telephone;
    std::string& postcode;

    person() : forename(vars[0]) ,
               surname(vars[1]) ,
               telephone(vars[2]) ,
               postcode(vars[3])
    {}
};

I'd still question as to exactly why you feel need to switch between data members at runtime, but references are a cleaner solution than macros at least.

heh. Topic is going to hell but whatever.

I'm reading in XML data and have named my members and their attributes the same. So the XML element <element> has the attribute name. I read those attributes as strings, so that when I've read the attribute, I'll have 2 strings: one containing the attribute's name and one containing the value of that attribute:

"name" "10"

Then I want to change that variable to a integer and set the class member element::name to that integer (10). So, I compare the string to the element's member name (which is in this case "name") and if that's correct I set that member. :D

if(strAttrName == "name"){
    strAttrVal >> this->name;
}

because I don't want to write this 20 times, I created that macro:

#define setElementMember(x)\
            if(strAttrName == #x){\
                str >> this->x;\
            }

and I undefine it right after I don't need it anymore to make sure it doesn't get used anywhere else in the code.

Here's the final code:

//! Sets elements attrList AND the corresponding member variable.
    //! Current method does not allow setting of <char *> member variables due to the need for memory allocation. Necessary? (don't forget setName() )
    void element::setAttribute(const char *attrName, const char *value)
    {
        cout << "Setting " << attrName << " to " << value << endl;

        map<string, string>::iterator it = attrList.find(attrName);

        if(it != attrList.end())
        {
           attrList.erase(it);
           attrList[attrName] = value;
        }

        string strAttrName(attrName);
        string strValue(value);
        stringstream str(strValue);

        #define setElementMember(x)\
            if(strAttrName == #x){\
                str >> this->x;\
            }
        setElementMember(x)
        else setElementMember(y)
        else setElementMember(width)
        else setElementMember(height)
        #undef setElementMember
    }
This article has been dead for over six months. Start a new discussion instead.