例外是 return 不同类型的合理方式吗?

would exceptions be a reasonable way to return different types?

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

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

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 作为失败的操作标志和类似的东西。想法?意见?我完全错过了什么吗?

绝对不是。你不会带剑到 table 去砍蔬菜 table。在这种情况下,它甚至不是剑。它是一把刷子。

开个玩笑,看看你想做什么,这意味着你已经知道 return 值的可能类型。既然如此,就用std::variant

Exceptions 应该用于异常而不是用于正常的条件代码部分。如果 "not online" 现在是一个例外是品味问题。

但是,如果您的问题更笼统,并且询问有关从单个函数返回不同 return 类型的问题,您应该考虑使用 std::variant. With std::holds_alternative you can ask which type was stored in the variant. There are several methods to deal with the content of variants e.g. 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...
}

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

struct payload_base_class : public std::exception
{
};

那我就知道你的这个模式会有用了。我已经规定了这种共性,因此您可以区分您的 return-flavor 异常和您应该以更标准的方式处理的异常。

(有可能你不希望std::exception作为基础class,否则你的异常可能会被无意中捕捉到,供你学习。)

此技术优于 std::variant 方法,因为您可以添加新的 return 类型而无需更改 std::variant 模板;后者会带来重大变化。

C++ 旨在允许此类攻击。仅仅因为人们在开发异常时没有考虑到这个用例,并不能使这种方法不合法。模板元编程也在无意中成长起来。