Sign in to follow this  
mopos

Finding the nPos of a vector where "str" is.

Recommended Posts

Hi, mCurrentRow is a std::vector<std::string> so is mFields. Now I'd like to convert the tFieldName into an integer so I can fetch the n- fields in the database row (mCurrentRow) however I'm not entirely sure how to do this. I've attempted to do it below. Any pointers would be nice. Thank you template <typename T> T SqlDataReader::get(const std::string& tFieldName) { T tRet; std::stringstream tSs; std::vector<std::string>::iterator tIt; unsigned int tPos; if (mCurrentRow.empty()) throw SqlException("the sqldatareader's current row is empty"); tIt = std::find(mFields.begin(), mFields.end(), tFieldName); if (tIt == mFields.end()) throw SqlException("cannot access that field"); else tPos = tIt - mCurrentRow.begin(); if (tPos > mFieldsCount) throw SqlException("cannot access that field"); tSs << mCurrentRow.at(tPos); try { if (!(tSs >> tRet)) throw SqlException("failed to convert"); } catch (std::exception &e) { throw SqlException(e.what()); } return tRet; }

Share this post


Link to post
Share on other sites
gdnet has [ source ][ /source ] tags, which will format your code correctly and make it easier to read. Anyway, you didn't really describe what the problem was, so maybe you could provide more info about any errors or incorrect behavior. Other than that I'd just mention that what you're doing towards the end of the function is nicely encapsulated in boost::lexical_cast<>(). Switching over might not solve the problem you're having, but it would definitely remove a possible source of error. lexical_cast<>() throws if the cast fails, so you can detect this case and handle it appropriately.

Share this post


Link to post
Share on other sites
Well, I can't follow what you're trying to do (partly no doubt because of your ridiculously generic and overly concise variable names), however, your error appears to be this line:

tPos = tIt - mCurrentRow.begin();

tIt is an iterator into mFields, mCurrentRow.begin() is an iterator into mCurrentRow. You cannot meaningfully subtract an iterator into one container from an iterator into another.

Σnigma

Share this post


Link to post
Share on other sites
I'd like to point out that it's rather silly to have a member that counts items in a vector, when the vector already has such a count. Unless that's supposed to be some kind of security scheme? Otherwise you're only making more work for yourself to keep that count value valid.

Anyway, yes, you can't do iterator arithmetic like that between iterators over different ranges. The difference taken within the one range will give you an appropriate index which you can use into the other vector.

And yeah, consider some other options for your naming conventions, and *please* declare your variables near first use and scoped appropriately - this isn't C. And since you presumably want rectangular data, you might want to look into Boost::multi_array. ALthough if this kind of "keyed" access is usual, you might consider other data structures altogether. For example, store the table as a std::map<std::string, std::vector<std::string> >, where the key is the column title and the value stores all the row values for that column in order.


// A typedef like this ought to already be provided within your class
typedef std::vector<std::string> table;
// ditto
typedef table::iterator table_iter;

template <typename T>
T SqlDataReader::get(const std::string& fieldname) {
// I assume you allow for the row to be empty as a special case to
// indicate "end of table" or something...
if (current_row.empty())
throw SqlException("the sqldatareader's current row is empty");

table_iter it = std::find(fields.begin(), fields.end(), fieldname);

if (it == fields.end())
throw SqlException("cannot access that field");

int index = it - fields.begin(); // not the row.begin()!

// If the table isn't rectangular, that is presumably a coding error...
assert(index < current_row.size());

stringstream ss;
try {
ss << current_row[index];
ss >> result;
} catch (std::exception &e) {
throw SqlException(e.what());
}
if (!ss) throw SqlException("failed to convert");

return result;
}


(And snk_kid is correct about the exceptions - I was wondering exactly what exception you were worried about there, but decided not to comment.)

[Edited by - Zahlman on May 24, 2006 2:18:23 PM]

Share this post


Link to post
Share on other sites
standard library streams don't throw exceptions by default, you need to enable/disable them using the exceptions method passing flags to indicate which exception types to enable/disable.

Share this post


Link to post
Share on other sites
Thank you all for the replies. To elaborate my problem I here have a similiar functino but that takes an integer as an argument



template <typename T>
T SqlDataReader::get(const unsigned int tField)
{
T tRet;
std::stringstream tSs;

if (mCurrentRow.empty())
throw SqlException("the sqldatareader's current row is empty");

if (tField > mFieldsCount)
throw SqlException("cannot access that field");

tSs << mCurrentRow.at(tField);

try
{
if (!(tSs >> tRet))
throw SqlException("failed to convert");
}
catch (std::exception &e)
{
throw SqlException(e.what());
}

return tRet;
}




As you can see that function fetches the n field from the current row and it works fine. The overloaded function i posted longer up basically just takes the field name as an argument instead and those are in mFields... so I need to translate the fieldname into the n element where that is.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this