安全bool多次转换歧义

时间:2015-12-17 12:29:17

标签: c++ safe-bool-idiom

我必须实现安全的bool习惯用法,以支持没有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()的实现,一切正常。问题实际上是在"安全布尔"中出现了模糊的可兑换性问题。基于实施。该如何解决?

注意:考虑将bool转换实现独立于其他指针转换实现。如果不可能给我一个线索如何在依赖的情况下实现它,例如if Convertible如果其中一个转换运算符返回非空值,则求值为true。

UPD:我相信有一种方法可以让一个隐式转换比另一个更优选。

2 个答案:

答案 0 :(得分:1)

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

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

但由于您拥有int*double*的运算符,您仍然会进行模糊转换。这部分可能需要重新设计,因为不清楚如何将单个值隐式转换为多个不相关的指针类型。

答案 1 :(得分:0)

实际上没有好的解决方案。我发现一个部分满足我的要求并且管理其他要求会削弱。

根据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存在(来自'安全布尔'实现)。

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