c++ - 自定义转换运算符的 Clang 歧义

标签 c++ c++11 decorator move

我一直在开发一种适配器类,当我在 clang 下遇到问题。当定义了左值引用和右值引用的转换运算符时,您会在尝试从您的类中移出时遇到歧义编译错误(当这样的代码应该没问题时,如

operator const T& () const&

仅允许用于左值 AFAIK)。我用简单的例子重现了错误:

#include <string>

class StringDecorator
{
public:
  StringDecorator()
  : m_string( "String data here" )
  {}

  operator const std::string& () const& // lvalue only
  {
    return m_string;
  }

  operator std::string&& () && // rvalue only
  {
    return std::move( m_string );
  }

private:
    std::string m_string;
};

void func( const std::string& ) {}
void func( std::string&& ) {}

int main(int argc, char** argv)
{
  StringDecorator my_string;

  func( my_string ); // fine, operator std::string&& not allowed
  func( std::move( my_string ) ); // error "ambiguous function call"
}

在 gcc 4.9+ 上编译良好,在任何 clang 版本上编译失败。 所以问题是:有什么解决方法吗?我对 const& 函数修饰符的理解正确吗?

P.S.:为了澄清 - 问题是关于修复 StringDecorator 类本身(或为此类找到解决方法,就好像是库代码一样)。请不要提供直接调用运算符 T&&() 或明确指定转换类型的答案。

最佳答案

问题来自最佳可行函数的选择。在第二次 func 调用的情况下,它意味着比较 2 个用户定义的转换序列。不幸的是,如果 2 个用户定义的转换序列不使用相同的用户定义的转换函数或构造函数,它们将无法区分 C++ standard [over.ics.rank/3]:

Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

  • [...]

  • User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function or constructor [...]

因为右值总是可以绑定(bind)到 const 左值引用,所以如果函数为 const std::string&std::重载,您无论如何都会陷入这种模棱两可的调用:字符串&&.

正如您所提到的,我的第一个答案是重新声明所有函数,这不是解决方案,因为您正在实现一个库。事实上,不可能为所有以 string 作为参数的函数定义代理函数!!

这样您就可以在 2 个不完美的解决方案之间进行权衡:

  1. 您删除 operator std::string&&() &&,您将失去一些优化,或者;

  2. 您公开继承自 std::string,并删除 2 个转换函数,在这种情况下,您的库会被滥用:

    #include <string>
    
    class StringDecorator
      : public std::string
    {
    public:
      StringDecorator()
      : std::string("String data here" )
      {}
    };
    
    void func( const std::string& ) {}
    void func( std::string&& ) {}
    
    int main(int argc, char** argv)
    {
      StringDecorator my_string;
    
      func( my_string ); // fine, operator std::string&& not allowed
      func( std::move( my_string  )); // No more bug:
        //ranking of standard conversion sequence is fine-grained.
    }
    

另一种解决方案是不使用 Clang,因为它是 bug of Clang .

但如果您必须使用 Clang,Tony Frolov 的答案就是解决方案。

关于c++ - 自定义转换运算符的 Clang 歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47658431/

相关文章:

c++ - 是否还可以自定义STL vector 的 "reference"类型?

c++ - winsock 客户端套接字无效

multithreading - 当 main 退出时,控制台输出到哪里?

c++ - std::string 和字符串文字之间的不一致

python - 将惰性求值转换为装饰器 (Python)

c++ - 构建 VBA-M 时的 stdlib.h 和 cstdlib 错误

c++ - CUDA 运行时错误 4 - 从 CUDA 3.2 更新到 CUDA4 后出现

c++ - 使用 mouseMoveEvent 限制 QGraphicsItem 的移动

python - 识别等效的可变参数函数调用以进行内存

types - SQL Alchemy - 使用 TypeDecorator 进行模式提取