【发布时间】:2013-03-13 13:44:32
【问题描述】:
我正在尝试将使用 Visual Studio 2005 构建的旧项目更新为使用 Visual Studio 2012,但我遇到了无法解决的错误。
VS2005下运行良好的代码:
#include <iostream>
#include <string>
#include <sstream>
using std::cout;
using std::wcout;
using std::endl;
using std::wstring;
using std::string;
class Value
{
public:
Value(const wstring& value)
{
v = value;
}
Value(Value& other)
{
this->v = other.v;
}
template<typename T>
operator T() const
{
T reply;
std::wistringstream is;
is.str(v);
is >> reply;
return reply;
}
operator wstring() const
{
return v;
}
private:
wstring v;
};
int main()
{
Value v(L"Hello World");
wstring str = v;
wcout << str << endl;
Value int_val(L"1");
int i = int_val;
cout << i + 1 << endl;
return 0;
}
当我在 VS2012 下编译时,“wstring str = v;”行出现错误,错误是:
error C2440: 'initializing' : cannot convert from 'Value' to 'std::basic_string<_Elem,_Traits,_Alloc>'
1> with
1> [
1> _Elem=wchar_t,
1> _Traits=std::char_traits<wchar_t>,
1> _Alloc=std::allocator<wchar_t>
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
我可以通过将运算符签名从“operator wstring() const”更改为“operator const wstring&() const”来修复它。但是为什么原来的代码在VS2005下也能用,还是不能用。
我在“int i = int_val;”行没有收到错误。
这也可以在 cygwin(版本 4.5.3)中使用 GCC (g++) 编译和运行。
更新 为了真正模拟我的实际问题,上面的示例代码中遗漏了一些信息。在值类和用法之间是一些其他类。一个看起来像这样:
class Config
{
public:
virtual Value getValue(const string& key) const = 0;
Value operator()(const string& key)
{
return getValue(key);
}
};
以及用法 const wstring value2 = config("key");
这将在编译时给出上述错误,但 IntelliSense 也会给出其他错误提示,并显示:“从“Value”到“const std::wstring”的不止一个用户定义的转换适用:”并且它指向 basic_string 的常规构造函数和移动构造函数。所以它似乎与 rvalues 做有关,我一直在阅读,并了解基础知识。但我可能缺少很多东西。
我发现我可以通过将用法更改为: const wstring&& value = config("key");
然后看起来VS2012编译器知道它应该使用哪个构造函数。
问题: * 有没有办法在这个例子中不使用 &&? * 这里到底发生了什么?
我在 GitHub 上放了示例代码: https://github.com/Discordia/ImplicitTypeConversion
【问题讨论】:
-
用 Clang Trunk 编译得很好,所以我猜这是一个错误,因为它们的重载解决方案没有在模板之前选择非模板(跨越不同的可能 UCS)。请注意,有两种可行的构造函数:一种采用
wstring&&,另一种采用wchar_t const*。前者将调用wstring转换操作,而后者将调用转换操作模板。 -
@Xeo:或者是多个编译器中的一个常见错误。在标准中快速粗略地查看它似乎 VS 可能就在这里。我没有找到任何确定非模板版本优先于模板版本的规则,如果没有该优先级,转换运算符在转换为
std::wstring时会模棱两可,并且标准要求代码失败。 -
@David:
§13.3.3/1:"鉴于这些定义,一个可行函数F1被定义为比另一个可行函数F2更好的函数,如果 [...]F1是非模板函数,F2是函数模板特化 [...]" -
@Xeo:可能......不确定,因为整个段落是根据函数参数的转换来说明的,其中转换运算符没有。我猜你可以使用空的参数集,在这种情况下,空的转换集是相同的......
-
@David:介意加入我的休息室吗?我目前正在调查。
标签: c++ c++11 visual-studio-2012 rvalue