【问题标题】:Is there a way to dynamically change the return-type of a function in C++ based on function parameter values?有没有办法根据函数参数值动态更改 C++ 中函数的返回类型?
【发布时间】:2020-10-13 06:29:55
【问题描述】:

我正在处理一个问题,该问题需要我根据我提供的函数参数值返回不同的返回类型。

我想做这样的事情--

在下面的代码中,doSomething() 是一个已经存在的函数(被很多客户端使用),它以mode 作为函数参数,并且已经返回了std::list<ReturnType>

基于模式值,我必须创建另一个返回shared_future<std::list<ReturnType>> 的子功能。

如何更改此代码,以便它可以根据模式值返回两种返回类型之一?

注意:ReturnType 是一个 template typename,我们将用于整个班级。

代码:

    std::shared_future<std::list<ReturnType> > futureValue() {
        return functionReturningSharedFuture();
    }
    
    std::list<ReturnType> listValue() {
        return functionReturningList();
    }
    std::list<ReturnType> doSomething(int mode) {
        if(mode == 1){
            // new functionality that I added
            return futureValue(); // This (obviously) errors out as of now
        }
        else{
            // already there previously
            return listValue();
        }
    }
    
    int main() {
        doSomething(1);
        return 0;
    }

如何更改此代码,以便它可以根据模式值返回两种返回类型之一?

限制和问题:

  1. 如果我们提供一个额外的函数参数(如true 值),这个问题可以通过函数重载轻松解决,但是这个额外的参数没有用,因为我们已经在使用mode。此外,添加几乎没有用的变量也不是一个好的设计。
  2. 主要限制之一是已经在使用此doSomething() 的客户期望std::list&lt;ReturnType&gt;,因此我无法返回boost::anystd::variant 或类似的东西。
  3. 我尝试使用 std::enable_if,但由于我们在运行时获取模式值,因此没有成功。
  4. 我们不能使用模板元编程,因为这会改变我们在客户端调用函数的方式。我们负担不起的事情。

谢谢。

【问题讨论】:

  • 类型在编译时固定,而变量的值在运行时设置。没有多态类型是不可能的。您需要解决的实际和潜在问题是什么?为什么您认为这是最好的(或唯一的)解决方案?
  • 不如简单地创建一个全新的函数,命名为doSomethingEx,并将新的行为记录给用户。如果他们想使用它,那很好,如果他们想坚持使用 doSomething 的旧方式,什么都不会被破坏。试图在现有函数中硬塞特征或额外的东西很多时候是行不通的。

标签: c++ c++11 c++14 c++17


【解决方案1】:

这是做不到的。

您只能拥有一个具有给定签名的函数。如果您的调用代码已经期望它返回std::list&lt;ReturnType&gt;,就是这样;你已经完成了。

如果你能保证所有现有的调用代码看起来像

auto l = obj.doSomething(1);

那么您可能会将返回类型更改为看起来类似于std::list 的任何调用代码。但是如果有 any 调用代码看起来像

std::list<ReturnType> l = obj.doSomething(1);

那就不说了。

您可能需要在这里重新考虑您的设计。

【讨论】:

  • “我认为使用 auto 在单个函数中不可能有两种不同的返回类型”这是正确的——正如我在答案中所说,每个签名只有一个重载,在turn 表示返回类型由签名确定——但据我所知,与我的答案无关。
  • 对不起,我的错,你完全正确。我读得不够仔细。
【解决方案2】:

从示例main,我看到doSomething(1);,所以也许在调用站点参数mode 的值在编译时总是已知的。在这种情况下,一种选择是让doSomething 成为template&lt;int mode&gt; 函数。我正在考虑这样的事情:

#include <iostream>
#include <list>
#include <vector>

// assuming you cannot change this (actually you have changed it in you example, ...)
std::list<int> doSomething(int mode) {
    std::cout << "already existing function\n";
    return std::list<int>{1,2,3};
}

// then you can put this too
template<int N>
auto doSomething();

template<>
auto doSomething<10>() {
    std::cout << "new function\n";
    return std::vector<int>{1,2,3};
}

int main() {
    auto x = doSomething(3);
    auto y = doSomething<10>();
}

可能另一种选择是在if 中使用if constexpr 而不是auto/decltype(auto)doSomething 中返回类型,但我还没有尝试过。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多