views:

88

answers:

4

I'm getting the following error when I compile the following code on Visual Studio 2008 / Windows SDK 7

const UINT a_uint;
UINT result;

throw std::runtime_error( std::string("we did ") + a_uint +
                          " and got " + result );

Ironically, I ended up with this result:

error C2782: 'std::basic_string<_Elem,_Traits,_Alloc> std::operator +(
                 const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem
             )' : template parameter '_Elem' is ambiguous

Can someone explain what's going on here?

+5  A: 

You can reduce that to this

template<typename T>
void f(T, T);

int main() {
 f('0', 0); // is T int or char?
}

You try to add an unsigned int to a string. That does not make sense, and the std::string class does not need to take any precautions to add implicit conversions to char here because that would hide such potential programming bugs.

Try to convert the unsigned int to std::string into a decimal/hexadecimal/octal/etc form and then concatenate (you can do that using std::ostringstream or boost::lexical_cast) or fix the bug in other ways you see fit.

Johannes Schaub - litb
A: 

Next time please post the full error (it should continue "with [ _Elem = ], could be one of [list of ambiguous overloads]").
The problem is that you concatenate UINT with a std::string. This is not a valid operation, you first have to convert the UINT to a std::string (search Google for handy functions). The compiler is trying to do its best and tries to match some of the std::string operators to the UINT. Apparently, it finds some matches but these certainly aren't what you are looking for.

dark_charlie
It didn't say anything else.
A Student at a University
Hmm, it should have. What version of Visual C++ do you use? VC++ 2008 always lists the types involved for me.
dark_charlie
+2  A: 

Use stringstream (defined in the sstream header) to compose the error message:

std::stringstream ss;
ss << "we did " << a_uint << " and got " << result;
throw std::runtime_error(ss.str());
FredOverflow
A: 

To a std::string, you can only add other std::strings, ASCIIZ text at an address specified by a const char*, and individual char-acters.

To concatenate other types, you can:

  • use a stream:

    std::ostringstream oss; oss << "we did " << a_uint << " and got " << result; throw std::runtime_error(oss.str());

  • convert it first to a string representation:

    throw std::runtime_error(std::string("we did ") + boost::lexical_cast(a_uint) + " and got " + boost::lexical_cast(result));

You might reasonably wonder why C++ doesn't provide operator+(std::string&, X&) for X in { short, int, long, long long, float, double, unsigned short etc. }, or even:

template <typename T>
std::string operator+(std::string& s, T& t)
{
    std::ostringstream oss;
    oss << t;
    return s + oss.str();
}

In many cases it would be convenient. But streams are more powerful as you can tune the padding width and character, floating point precision etc.. Further, char is the 8-bit integer type, so how could the compiler know whether to append a single character with that ASCII value (e.g. 'A' for 65), or an ASCII representation of the numeric ASCII value "65"? (Currently it doesn't handle any ints, so treating it as a single ASCII char isn't confusing). Or should it work for >=16 bit numbers but not 8? That would make it impossible to resize variables to/from 8-bit ints without having to do a complex impact analysis to see which string operations needed to be rewritten. It's also good practice to minimise dependencies: some small but perhaps significant percentage of translation units using string may not currently have to include (and hence spend time parsing) (and hence ostream etc), and in general cyclic dependencies are a "code smell" and frustrate testability (string depends on ostringstream depends on string...).

Tony