为什么隐式转换不能累积?

时间:2017-06-16 05:48:21

标签: c++ string templates implicit-conversion

这是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函数const char *的调用中使用从stringaccumulate的隐式转换。我知道从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。

3 个答案:

答案 0 :(得分:12)

std::accumulate被声明为

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

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

您可以显式传递std::string,或明确指定模板参数。 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(), "");

答案 1 :(得分:11)

查看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;
}

当您按照自己的方式调用该函数时,InputIt将被推断为vector<string>::const_iterator,而T将被推断为const char*。正如你在for循环中看到的那样,执行&#34;积累&#34;的代码行。是这个

init = init + *first

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

这不起作用,因为std::string对象不可隐式转换或可分配const char*,但反之亦然。

要解决此问题,请将您的代码更改为以下内容(请注意,我使用s对字符串文字进行了后缀,这是用户定义文字的C ++ 14语法(在本例中计算结果为{{ 1}})http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s

std::string

同样为noted in the comments,将int main() { using namespace std::string_literals; vector<string> v; string sum = accumulate(v.cbegin(), v.cend(), ""s); } 更改为void main()。有关详情,请参阅What should main() return in C and C++?

答案 2 :(得分:2)

  

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

甚至没有尝试进行隐式转换,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

相关问题