This is the C++ program:
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int test_string(const string & str) {
    return str.size();
}
void main() {
    test_string("");                                     //can compile
    vector<string> v;
    string sum = accumulate(v.cbegin(), v.cend(), "");   //cannot compile
}
I want to use implicit conversion from const char * to string in the call of generic STL function accumulate. I know that conversion from const char * to string is not explicit, so we can pass const char * parameter to calls in which a string type is required. This can be proved by the above test_string function. But when I did the same thing in accumulate, the compiler complain:
error C2440: '=': cannot convert from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'const char *'
The code works only when I replaced "" with string(""). I don't understand why the implicit conversion works for my custom function but does not work in accumulate. Can you explain that? Thanks a lot.
PS: I am using Visual Studio 2015.
std::accumulate is declared as
template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );
That means the template argument T is deduced from the argument passed in (i.e. ""). Then it'll be const char*. On the other hand, how could the compiler perform the implicit conversion? Which type should be the target type?
You can pass a std::string explicitly, or specify the template argument explicitly. e.g.
// pass a std::string exactly
string sum = accumulate(v.cbegin(), v.cend(), string(""));
// T is specified as std::string explicitly
// "" will be implicitly converted to std::string
string sum = accumulate<decltype(v.cbegin()), string>(v.cbegin(), v.cend(), "");
                        Take a look at the possible implementation from cppreference
template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init)
{
    for (; first != last; ++first) {
        init = init + *first;
    }
    return init;
}
When you call the function the way you did, InputIt will be deduced as a vector<string>::const_iterator and T will be deduced to be a const char*.  As you can see here in the for loop, the line of code that does the "accumulation" is this
init = init + *first
Here on the right hand side of the assignment *first will evaluate to a string& and init will evaluate to a const char*.  Then you will be using the std::string::operator+ which will concatenate the const char* and the std::string instance to get a std::string back.  And then you are trying to assign a std::string to a const char* variable.  This is not legal.
This will not work as std::string objects are not implicitly convertible or assignable to const char*, the reverse is true however.  
To fix this change your code to the following (note that I postfixed the string literal with a s, which is C++14 syntax for a user defined literal (which in this case evaluates to a std::string) http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
int main() {
    using namespace std::string_literals;
    vector<string> v;
    string sum = accumulate(v.cbegin(), v.cend(), ""s); 
}
Also as noted in the comments, change void main() to int main().  For more see What should main() return in C and C++?
I don't understand why the implicit conversion works for my custom function but does not work in accumulate. Can you explain that?
Implicit conversion isn't even attempted, std::accumulate simply tries to accumulate by adding instances of std::string to a sum that's initialized as auto sum = ""; and you get the same error that you would get in this case:
std::string s = "abc";
const char* sum = "";
sum = sum + abc; // <-- error
The code works only when I replaced "" with string("")
Because this way internally accumulator's type is std::string and everything works as intended. You may as well do this:
string sum = accumulate(v.cbegin(), v.cend(), ""s);
As a side note, it should be int main() { ... }, not void main
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With