安全布尔多次转换歧义

Safe bool multiple conversions ambiguity

本文关键字:歧义 转换 布尔多 安全      更新时间:2023-10-16

为了支持没有explicit关键字的编译器(例如MSVC 2012),我必须实现安全布尔习惯用法。对于bool,应该是可检查的类正在建模指向许多类的指针,因此它应该可以转换为这些指针。下面的代码说明了这个想法:

// Uncomment this line to change implementation to 'safe bool'
// #define _COMPILER_NO_EXPLICIT
#if !defined(_COMPILER_NO_EXPLICIT)
#define OPERATOR_BOOL_MYTYPE(...)
#define OPERATOR_BOOL_IMPLEMENTATION(...) 
    public: 
            explicit operator bool() const noexcept 
            { 
                    return __VA_ARGS__; 
            }
#else
#define OPERATOR_BOOL_MYTYPE(...) 
    private: 
            void safe_bool() {}; 
            typedef __VA_ARGS__ safe_bool_my_type_t; 
            typedef void (safe_bool_my_type_t::*safe_bool_t)()
#define OPERATOR_BOOL_IMPLEMENTATION(...) 
    public: 
            operator safe_bool_t() const noexcept 
            { 
                    return __VA_ARGS__ ? 
                            &safe_bool_my_type_t::safe_bool : 
                            nullptr; 
            }
#endif

class Convertible
{
public:
    operator int*() const
    { return nullptr; }
    operator double*() const
    { return nullptr; }
    OPERATOR_BOOL_MYTYPE(Convertible);
    OPERATOR_BOOL_IMPLEMENTATION(false);
};

int main(void)
{
    Convertible a;
    if (a)
    {
        // this 'if' statement introduces compilation error
        // in 'safe bool' implementation
    }
    return 0;
}

如果我们使用基于explicit operator bool()的实现,一切都可以正常工作。问题实际上在于基于"安全布尔"的实现中不明确的可转换性。应该如何解决?

注意:考虑布尔转换实现独立于其他到指针的转换实现。如果不可能,请告诉我如何在依赖情况下实现它,例如,如果Convertible评估为true,则当其他转换运算符之一返回非零值时。

UPD:我相信有一种方法可以使一个隐式转换比其他所有隐式转换更可取。

您是否确定需要隐式转换为其他指针类型?如果你不需要,问题就会消失。

如果你确实需要隐式转换为指针类型,那么这个问题似乎没有意义:你不需要转换为bool,因为转换为指针也会产生一个可以进行真值测试的值(就像普通的原始指针一样)。

但是,由于int*double*都有运算符,因此仍然存在不明确的转换。这部分可能需要重新设计,因为尚不清楚如何将单个值隐式转换为多个不相关的指针类型。

实际上没有好的解决方案。我发现一个部分满足我的需求,并设法削弱了其他需求。

根据http://en.cppreference.com/w/cpp/language/implicit_cast隐式转换的集合和顺序如下:

1) 零或一个标准转换序列

2) 零或一个用户定义的转换

3) 零或一个标准转换序列

由于问题中的两种类型的转换都是用户定义的,并且都允许进一步标准转换为bool,我决定将operator int*()operator double*()转换函数更改为其他operator Ptr<int>()operator Ptr<double>,其中Ptr<T>是一个模板类,其行为与原始指针相同。特别是它可以转换为bool,但这并不重要,因为这是第二次用户转换,因此它是被禁止的。因此,存在到bool的唯一转换(来自"安全布尔"实现)。

此解决方案的缺点是需要客户端代码来更改接口或执行对原始指针的显式强制转换。