【问题标题】:C++11 vs C++98 conversion operator behavior changes?C++11 与 C++98 转换运算符的行为变化?
【发布时间】:2015-02-13 22:50:05
【问题描述】:

我希望在一些现有的 c++ 项目中使用一些 c++11 功能,因此我开始为一些项目更改 Clang 中的编译标志,并且我一直遇到有关 C++11 处理转换运算符的特定问题(或强制转换运算符)我没想到会看到并且不明白为什么当它是不是 c++11 的有效 C++ 代码时现在将其视为错误

我把它归结为这个简单的例子:

#include <iostream>
#include <vector>

class SerializableFormat
{
public:
    size_t i;
};

class A
{
public:
    size_t x, y;

    A(size_t n) : x(n), y(1) { }

    operator const SerializableFormat() const
    {
        SerializableFormat result;

        result.i = x;

        if (y)
        {
            result.i /= y;
        }

        return result;
    }
};

int main(int argc, const char * argv[])
{
    std::vector<SerializableFormat> v;

    for(size_t i = 0; i < 20; i++)
    {
        v.push_back(A(i));
    }

    return 0;
}
  • 如果 Clang 的编译标志设置为 -std=c++98libstdc++,则没有问题,并且编译正常。
  • 如果 Clang 的编译标志设置为 -std=c++11libc++,我会收到错误 No viable conversion from 'A' to 'value_type' (aka 'SerializableFormat')

只是为了说清楚——如果你正在考虑为类A 提供一个构造函数 SerializableFormat:

由于SerializableFormat 类更适合于各种类之间的转换,因此A(以及其他希望可序列化的类)拥有构造函数和转换运算符而不是期望SerializableFormat 是有意义的涵盖所有想要可序列化的类,因此修改SerializableFormat 使其具有特殊的构造函数不是解决方案。

谁能看到我在这里做错了什么?

【问题讨论】:

  • 使用 GCC、libstdc++ 和 -std=c++11,它仍然可以编译。您的转换运算符返回const SerializableFormat 没有意义——只需返回SerializableFormat,它也适用于clang——但我不知道您的代码是否有效。
  • 直到刚才我才注意到 LLVM 标签。这改变了一切。
  • 最小测试用例:struct A { }; struct B { operator const A(); }; void f() { (A(B())); } 在所有模式下都被 GCC 接受,仅在 C++03 模式下由 clang 接受。

标签: c++ c++11 llvm libstdc++ libc++


【解决方案1】:

正如 cmets 正确指出的那样,您可以通过在您的 SerializableFormat 转换运算符的返回类型中删除 const 来进行编译:

operator const SerializableFormat() const

至于clang在这种行为上是否正确是一个有争议的问题。 clang bug report 16682 正在跟踪该问题。目前有关于创建 CWG(C++ 委员会)问题报告的讨论,但尚未完成。我注意到这个错误报告已经开放了一段时间(2013-07-23),但最近更新到 2015-01-28。

与此同时,实用的建议是永远不要通过const-value 返回。这对 C++98/03 来说是不错的建议,但使用移动语义会变成不好的建议,因为它会禁用移动语义。

【讨论】:

  • 为什么你会发现有必要首先返回一个const 对象?你在现场建造它,没有必要保护它。如果您要返回 reference,那就另当别论了。
  • @MarkRansom:在 C++98/03 中,一条准则建议始终以 const 返回以防止意外分配给右值(如果右值是 const,编译器会阻止它)。该指南在 Scott Meyers Effective C++ Item 3 中永垂不朽。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 1970-01-01
  • 2014-08-16
  • 2012-10-17
  • 2012-01-27
  • 1970-01-01
相关资源
最近更新 更多