【问题标题】:C++ type cast operator code that won't compile in visual studio 2012, but worked fine in visual studio 2005在 Visual Studio 2012 中无法编译但在 Visual Studio 2005 中运行良好的 C++ 类型转换运算符代码
【发布时间】: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&amp;&amp;,另一种采用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


【解决方案1】:

用简单的(希望不是简化的)术语,使用 C++11,您必须开始考虑左值和右值的引用。基本上,C++11 使您能够根据是否处理“临时”对象以不同方式处理引用操作。这使您能够执行诸如在对象内部移动数据之类的操作,而不是在不同情况下进行复制。不利的一面是您看到的效果,旧代码对您正在处理的内容不够具体。不仅如此,这并不是一个可以在简短的 SO 答案中完全解释的东西,但之前的 answers 给出了一些 good places 开始。我会重新编写你的代码以提供右值和左值运算符(听起来你已经在做这件事了)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多