【问题标题】:C++ equivalent for C#'s "?." null conditional operator [duplicate]C# 的“?”等价于 C++。空条件运算符 [重复]
【发布时间】:2019-11-01 16:51:57
【问题描述】:

在 C# 中有一个空条件运算符?.:

MyObject o = null;

o?.doSomeThing();

这意味着:

if(o != null)
    o.doSomeThing();

我想在 C++ 中有类似的东西:

MyObject* o = nullptr;

o?>doSomeThing(); // or o?->

这样写会很有用:

o?.getO()?.getO()?.doSomeThing();

所以我有两个问题:

  1. 今天我们使用宏进行单行条件执行。 C++14 中是否有不使用宏的简便方法?
  2. 是否有任何讨论或建议?我什么都没找到。

【问题讨论】:

  • 不,@oznog std::optional 不会做任何此类或任何类似的事情。
  • @PaulR 如果 doSomeThing 返回无法转换为 bool 的内容(我认为),则该操作不起作用。但否则这是一个很好的解决方案,因为链接可以工作。
  • @JesperJuhl if(o && o->getO() && o->getO()->getO()) o->getO()->getO()->doSomeThing(); 好吧,这是语法糖...
  • 我对 Jesper 的回答是否定的,必须是:if(o) if(auto o1 = o->getO()) if(auto o2 = o1->getO()) o2->doSomeThing(); 否则 getter 会执行两次,第二次执行可能会返回 nullptr 或其他对象。我不会把它写成一个班轮。

标签: c++ operators


【解决方案1】:

不,没有语法可以做到这一点,也没有办法创建所说的语法。

同样没有建议(据我所知)添加它。

相反,自己写出空检查,或者更好的是通过重组代码以减少事物可能为“空”的地方的数量,这样你就不需要它们了.

【讨论】:

    【解决方案2】:

    WRT 问题 #1:

    constexprinline 函数是宏函数的类型安全 C++ 等效项。它们不能保证内联您的代码,但它们允许编译器根据需要进行复制,并且积极的编译器将为您进行内联。许多标准库类都做出了这种假设(例如std::vector<T>::size())。

    编辑:好的,你们很顽皮,但很公平。下面是一种使用它来解决这个问题的方法:

    编辑:按要求更新为在 C++14 中编译。我知道这已被标记为重复,没有人会看它,但其他链接仅 C++17。它还在非指针成员上终止,并返回一个指向它们的指针,这更符合 C#,将值类型转换为 Nullable。

    #include <cstdio>
    #include <type_traits>
    
    template <typename Class>
    struct SafePtrImpl { 
        Class* ptr;
    
        SafePtrImpl(Class* ptr) : ptr(ptr) { }
    
        template <typename TClass, typename TResult, std::enable_if_t<std::is_pointer<TResult>::value, std::nullptr_t> = nullptr>
        inline SafePtrImpl<
            std::remove_pointer_t<
                std::remove_reference_t<
                    TResult>>> operator ->*(TResult TClass::*member) {
            return SafePtr(ptr ? ptr->*member : nullptr);
        }
    
        template <typename TClass, typename TResult, std::enable_if_t<!std::is_pointer<TResult>::value, std::nullptr_t> = nullptr>
        inline TResult* operator ->*(TResult TClass::*member) {
            return ptr ? &(ptr->*member) : nullptr;
        }
    };
    
    template <typename TClass>
    SafePtrImpl<TClass> SafePtr(TClass* ptr) { return SafePtrImpl<TClass>(ptr); }
    
    // --
    
    struct Foo {
        int x;
    };
    
    struct Bar {
        Foo* y;
    };
    
    int main() {
        Foo a { 42 };
        Bar b { &a };
        Bar c { nullptr };
        Bar* d = nullptr;
    
        int* b_y_x = SafePtr(&b)->*&Bar::y->*&Foo::x;
        int* c_y_x = SafePtr(&c)->*&Bar::y->*&Foo::x;
        int* d_y_x = SafePtr(d)->*&Bar::y->*&Foo::x;
        printf("b: %08x %d\n", b_y_x, *b_y_x);
        printf("c: %08x\n", c_y_x);
        printf("d: %08x\n", d_y_x);
    
        return 0;
    }
    

    https://godbolt.org/z/RYZ1EV

    输出:

    b: 3aa42aec 42
    c: 00000000
    d: 00000000
    

    【讨论】:

    • 好吧,我咬一口。已编辑。
    • @parktomatomi 谢谢。但我看不到你帖子的任何部分回答了我的问题。
    猜你喜欢
    • 2015-08-04
    • 2013-10-26
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2014-08-09
    相关资源
    最近更新 更多