为什么隐式转换在累积中不起作用?

Why does implicit conversion not work in accumulate?

本文关键字:不起作用 转换 为什么      更新时间:2023-10-16

这是C++程序:

#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
}

我想在通用 STL 函数accumulate的调用中使用从const char *string的隐式转换。我知道从const char *到字符串的转换不是显式的,因此我们可以将const char *参数传递给需要string类型的调用。这可以通过上述test_string函数来证明。但是当我在accumulate中做同样的事情时,编译器抱怨:

error C2440: '=': cannot convert from 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' to 'const char *'

仅当我将""替换为string("")时,代码才有效。我不明白为什么隐式转换适用于我的自定义函数,但在accumulate中不起作用。你能解释一下吗?多谢。

PS:我正在使用Visual Studio 2015。

std::accumulate 声明为

template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );

这意味着模板参数T是从传入的参数中推导出来的(即"")。然后它会const char*.另一方面,编译器如何执行隐式转换?哪种类型应该是目标类型?

您可以显式传递std::string,也可以显式指定模板参数。

// 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(), "");

看看 cpp偏好的可能实现

template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init)
{
for (; first != last; ++first) {
init = init + *first;
}
return init;
}

当您以 DO 方式调用函数时,InputIt将被推导为vector<string>::const_iteratorT将被推导为const char*。 正如你在 for 循环中看到的,执行"累积"的代码行是这样的

init = init + *first

在作业的右侧,*first将评估为string&init将评估为const char*。 然后,您将使用连接const char*std::string实例的std::string::operator+来获取std::string。 然后,您正在尝试将std::string分配给const char*变量。 这是不合法的。

这不起作用,因为std::string对象不是隐式可转换或可分配给const char*的,但情况正好相反。

要解决此问题,请将您的代码更改为以下内容(请注意,我在字符串文字后加上了s,这是用户定义文字(在本例中计算为std::string)的 C++14 语法 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); 
}

另如评论中所述,void main()更改为int main()。 有关更多信息,请参阅 main() 在 C 和 C++ 中应该返回什么?

我不明白为什么隐式转换适用于我的自定义函数,但在累积中不起作用。你能解释一下吗?

甚至没有尝试隐式转换,std::accumulate 只是尝试通过将std::string实例添加到初始化为auto sum = "";的总和来累积,并且您会收到与在这种情况下相同的错误:

std::string s = "abc";
const char* sum = "";
sum = sum + abc; // <-- error

仅当我用字符串(")替换"时,代码才有效

因为这种方式内部累加器的类型是std::string的,一切都按预期工作。你也可以这样做:

string sum = accumulate(v.cbegin(), v.cend(), ""s);

作为旁注,它应该是int main() { ... },而不是void main