【问题标题】:Clang error: ambiguous conversion for static_castClang 错误:static_cast 的模棱两可的转换
【发布时间】:2012-03-28 11:35:19
【问题描述】:

我有以下代码:

typedef int AliasB;
typedef unsigned short AliasA;

class Alias
{
public:
    explicit Alias(int someInt) { }

};

// (*) !! below breaks the conversion path via AliasA !!
//typedef Alias AliasA;

class C
{
public:
    C() { }
};

class B
{
public:
    B() { }
    B(const AliasB& value) { }

    operator AliasB() const
    {
        return -1000;
    }

    C combine(const B& someB) 
    {
        return C(); 
    }
};

class A
{
public:
    A() { }

    operator B() const
    {
         return B();
    }

    operator AliasA() const
    {
        return 1001;
        // (*) !! below breaks the conversion path via AliasA !!
        //return AliasA(1000);
    }

    A high() 
    {
        return A(); 
    }
    A low() 
    {
        return A(); 
    }

    C process()
    {
        return (static_cast<B>(low())).combine(static_cast<B>(high()));

        // (**) !! the below compiles fine !! 
        //B theB = low();
        //return theB.combine(high());
    }
};

inline int someFunc(unsigned int someParam, const B& bParam)
{
    return 1;
}

inline A createSomeA()
{
    return A();
}

int main ()
{
    A someA;
    unsigned int counter = 200;
    someFunc(counter, someA);
    //someFunc(counter, static_cast<B>(createSomeA()));
    someA.process();
    return 0;
}

Clang 报如下错误:

clang_static_test.cpp:66:17: error: ambiguous conversion for static_cast from 'A' to 'B'
        return (static_cast<B>(low())).combine(static_cast<B>(high()));
                ^~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
      ^
clang_static_test.cpp:25:5: note: candidate constructor
    B(const AliasB& value) { }
    ^
clang_static_test.cpp:66:48: error: ambiguous conversion for static_cast from 'A' to 'B'
        return (static_cast<B>(low())).combine(static_cast<B>(high()));
                                               ^~~~~~~~~~~~~~~~~~~~~~
clang_static_test.cpp:21:7: note: candidate is the implicit copy constructor
class B
      ^
clang_static_test.cpp:25:5: note: candidate constructor
    B(const AliasB& value) { }
    ^
2 errors generated.

我无法弄清楚为什么编译器会产生错误,尽管我有 定义了转换运算符,我使用 static_cast 在该特定位置进行了显式转换。 该代码通过 GCC 4.5.2 和 Visual Studio 2008 编译器的编译。 Clang 版本是 3.1,由我自己从 Clang 和 LLVM 的 git 存储库构建 几天前。

那么,Clang 是否报告了实际错误?如果是,为什么这是一个错误,因为它是 对我来说一点都不明显(我不会问为什么其他编译器对此保持沉默)?

更新:示例代码现在是一个小的可编译示例(很抱歉从第一次没有这样做)并复制了我的真实情况。 AliasA 的转换运算符似乎是问题所在,因为如果将其删除,则一切编译正常。现在令人讨厌的是,对于上面的代码,我也从 GCC 得到错误。

UPDATE 2:我在示例中添加了一些代码以更好地反映我的真实情况;唯一的区别是,对于上面的示例,我也从 GCC 得到一个错误,而对于我的真实代码,我没有。

【问题讨论】:

  • 可以出示someFunc的声明吗?
  • 可能需要显示更多代码才能找出答案(最好是一个小的可编译示例)。
  • AliasB的声明是什么?
  • @R. Martinho Fernandes 添加了函数声明。
  • 我发现隐式转换通常更烦人,因为它们是值得的。在这种情况下,您最好将构造函数或转换运算符设为explicit

标签: c++ casting clang


【解决方案1】:

static_cast 有两种方法可以将 A 转换为 B:

  1. 使用A::operator B并调用隐式复制构造函数B::B(const B&amp; value)来创建新的B

  2. 使用A::operator AliasA,将结果转换为AliasB并调用B::B(const AliasB&amp; value)

编译器不知道首选哪种方式。您可以通过以下方式提示使用第二个选项:

    someFunc(counter, static_cast<AliasA>(someA));

要使用第一个选项,您可以通过简单地编写来省略演员表:

    someFunc(counter, someA);

好吧,我不确定后者是否是明确定义的行为,但它至少适用于 gcc 和 msvc。

【讨论】:

    【解决方案2】:

    我已向 clang 提交了一份关于此问题的错误报告。他们认为这不是一个错误。 C++ 标准缺少针对这种情况的规范,因此编译器将其报告为模棱两可。见bug report

    我认为这种行为是违反直觉的。通过 A::operator B() 的第一条路径是完美匹配的,而第二条路径涉及三个类型转换。唯一合乎逻辑的事情就是认为完美的匹配是优越的。

    当 C++ 标准中没有明确解决案例时,编译器应该怎么做?

    1. 生成错误消息
    2. 类比其他规则做出合乎逻辑的选择
    3. 联系 C++ 标准委员会并告诉他们修改标准。

    ?

    【讨论】:

      【解决方案3】:

      我想我部分了解了正在发生的事情,但我不认为我理解整个情况。所以编译器看到的转换路径如下所示:

                    /--------  A  --------\
                    |                     |
                    |                     |
                    B             AliasA(unsigned short)
                    |                     |
                    |                     |
            copy ctor of B            AliasB(int)
                                          |
                                          |
                                 ctor B(const AliasB& value)
      

      所以这是有道理的,编译器在报告歧义方面是正确的(我喜欢 clan'g 错误和警告消息)。使其工作的一种方法是通过 AliasA 中断转换路径(请参阅问题示例代码中标有 (*) 的 cmets)。如果我打破有问题的表达式并仅依赖隐式转换,而不是尝试显式地 static_cast 任何东西,它也可以工作(请参阅问题示例代码中标有 (**) 的 cmets)。但我并不完全掌握幕后发生的事情。我仍然不完全理解为什么它在 (**) 的情况下表现不同,因为转换路径似乎是相同的,至少对于 "theB.combine(high() )" 部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-08-11
        • 1970-01-01
        • 2012-03-17
        • 1970-01-01
        • 1970-01-01
        • 2014-12-30
        • 2014-04-24
        相关资源
        最近更新 更多