【问题标题】:would exceptions be a reasonable way to return different types?异常是返回不同类型的合理方式吗?
【发布时间】:2020-03-16 09:19:10
【问题描述】:

我一直在想:由于异常可以是任何类型,它们是否可以根据条件返回不同的类型?

我知道这不是很清楚,所以我举个例子:对于一个消息传递应用程序,我们希望用户能够发送他们的位置,但出于隐私原因,我们希望它仅在用户是在线:

void get_user_position(User& u) {
    if(!u.is_online()) throw false;
    else throw u.get_position();
}

void send_user_position(User& u) {
    try {
        get_user_position(u);
    } catch(bool e) {
        //send a message like "user isn't online"
    } catch(user_position e) {
        //send the position
    }
}

这将避免需要 -1s 作为失败的操作标志和类似的东西。想法?意见?我完全错过了什么吗?

【问题讨论】:

  • 我更喜欢使用std::optional,这似乎是适合这项工作的错误工具。返回不同的类型不是静态类型语言中应该发生分支的地方。
  • @super 这只是我能想到的第一个例子,而不是实际的用例。无论如何,答案是std::variant
  • std::variant<std::monostate,user_position> 可能就是您要找的。​​span>

标签: c++ exception return-type


【解决方案1】:

异常应该用于异常而不是正常的条件代码部分。如果“不在线”现在是一个例外,那就是口味问题了。

但是,如果您的问题更笼统,并询问有关从单个函数返回不同返回类型的问题,您应该考虑使用 std::variant。使用std::holds_alternative,您可以询问哪种类型存储在变体中。有几种方法可以处理变体的内容,例如std::visit

struct A{};
struct B{};


std::variant < A,B > Func( int x)
{
    if ( x == 0 ) return A{};
    return B{};
}

int main()
{
    auto v = Func( 0 );
    if ( std::holds_alternative<A>(v) )
    {
        std::cout << "A" << std::endl;
    }
    else if ( std::holds_alternative<B>(v) )
    {
        std::cout << "B" << std::endl;
    }

    // or even use std::visit or whatever is helpful...
}

【讨论】:

    【解决方案2】:

    绝对不是。你不会把剑带到桌子上切菜。在这种情况下,它甚至不是剑。它是一把刷子。

    别开玩笑了,看看你想做什么,这意味着你已经知道返回值的可能类型是什么。既然如此,请使用std::variant

    【讨论】:

      【解决方案3】:

      只要您以这种方式使用的所有异常都派生自一个公共基类,例如

      struct payload_base_class : public std::exception
      {
      };
      

      那么我可以看到您的这种模式可能很有用。我已经规定了这种共性,因此您可以区分您的 return-flavour 例外和您应该以更标准的方式处理的例外。

      (你可能不希望std::exception作为基类,否则你的异常可能会被无意中捕获。这是你学习的。)

      std::variant 方法相比,此技术的优势在于您可以添加新的return 类型而无需更改std::variant 模板;后者可能会引入重大更改。

      C++ 旨在允许此类漏洞利用。仅仅因为人们在开发异常时没有考虑到这个用例并不意味着这种方法是非法的。模板元编程也是无意中成长起来的。

      【讨论】:

      • 我不能只在返回类型中使用auto 以避免每次都重写返回类型吗?
      猜你喜欢
      • 1970-01-01
      • 2018-09-22
      • 2014-04-25
      • 2016-10-27
      • 2022-12-12
      • 1970-01-01
      • 1970-01-01
      • 2011-07-31
      • 1970-01-01
      相关资源
      最近更新 更多