C++ 相同的函数参数具有不同的返回类型

问题描述 投票:0回答:11

我需要找到某种方法来模拟 C++ 中函数返回类型的重载。

我知道没有办法直接做到这一点,但我希望有一些开箱即用的方法。 我们正在创建一个 API 供用户使用,他们将传入一个数据字符串,该数据字符串根据字符串信息检索值。这些值是不同的类型。本质上,我们想让他们这样做:

int = RetrieveValue(dataString1);
double = RetrieveValue(dataString2);
// Obviously, since they don't know the type, they wouldn't use int =.... It would be:
AnotherFunction(RetrieveValue(dataString1)); // param of type int
AnotherFunction(RetrieveValue(dataString2)); // param of type double

但这在 C++ 中不起作用(显然)。 现在,我们正在设置它,以便他们调用:

int = RetrieveValueInt(dataString1);
double = RetrieveValueDouble(dataString2);

但是,我们不希望他们需要知道数据字符串的类型是什么。

不幸的是,我们不允许使用外部库,所以不能使用Boost。

我们有什么办法可以解决这个问题吗?

澄清一下,我知道 C++ 本身无法做到这一点。但一定有办法绕过它。例如,我考虑执行 RetrieveValue(dataString1, GetType(dataString1))。这并不能真正解决任何问题,因为 GetType 也只能有一种返回类型。但我需要这样的东西。

我知道这个问题以前曾被问过,但意义不同。我无法使用任何明显的答案。我需要一些完全开箱即用的东西才能对我有用,而其他问题中的任何答案都不是这种情况。

c++ function types overloading
11个回答
32
投票

你必须从这个开始:

template<typename T>
T RetrieveValue(std::string key)
{
     //get value and convert into T and return it
}

要支持此功能,您需要做更多工作,以便将值转换为类型

T
。转换价值的一种简单方法可能是这样的:

template<typename T>
T RetrieveValue(std::string key)
{
     //get value
      std::string value = get_value(key, etc);

      std::stringstream ss(value);
      T convertedValue;
      if ( ss >> convertedValue ) return convertedValue;
      else throw std::runtime_error("conversion failed");
}

请注意,您仍然必须将此函数调用为:

int x = RetrieveValue<int>(key);

如果你可以这样做的话,你可以避免两次提及

int

Value RetrieveValue(std::string key)
{
     //get value
      std::string value = get_value(key, etc);
      return { value };
}

其中

Value
实现为:

struct Value
{
    std::string _value;

    template<typename T>
    operator T() const   //implicitly convert into T
    {
       std::stringstream ss(_value);
       T convertedValue;
       if ( ss >> convertedValue ) return convertedValue;
       else throw std::runtime_error("conversion failed");
    }
}

那么你可以这样写:

int    x = RetrieveValue(key1);
double y = RetrieveValue(key2);

哪个是你想要的,对吧?


3
投票

唯一明智的方法是将返回值移至参数。

 void retrieve_value(std::string s, double& p);
 void retrieve_value(std::string s, int& p);
 <...>

 double x;
 retrieve_value(data_string1, x);

 int y;
 retrieve_value(data_string2, y);

2
投票

无论是重载还是专门化,您都需要将信息包含在函数签名中。您可以将变量作为未使用的第二个参数传递:

int RetrieveValue(const std::string& s, const int&) {
  return atoi(s.c_str());
}
double RetrieveValue(const std::string& s, const double&) {
  return atof(s.c_str());
}

int i = RetrieveValue(dataString1, i);
double d = RetrieveValue(dataString2, d);

1
投票

如果你知道你的值永远不会为零或负数,只需返回一个包含 int 和 double 的结构,并将不需要的值归零...

这是一种便宜又脏但简单的方法......

struct MyStruct{
int myInt;
double myDouble;
};

MyStruct MyFunction(){
}

1
投票

如果数据字符串是编译时常量(如回答我的评论中所述),您可以使用一些模板魔法来完成这项工作。一个更简单的选择是根本不使用字符串,而是使用一些允许您重载参数的数据类型。

struct retrieve_int {} as_int;
struct retrieve_double {} as_double;

int RetrieveValue(retrieve_int) { return 3; }
double RetrieveValue(retrieve_double) { return 7.0; }

auto x = RetrieveValue(as_int);    // x is int
auto y = RetrieveValue(as_double); // y is double

0
投票

不幸的是,没有办法重载函数返回类型,请参阅此答案 按返回类型重载


0
投票
int a=itoa(retrieveValue(dataString));
double a=ftoa(retrieveValue(dataString));

两者都返回一个字符串。


0
投票

作为模板解决方案的替代方案,您可以让函数返回指向类的引用或指针,然后创建该类的子类以包含您想要返回的不同数据类型。然后

RetrieveValue
将返回对适当子类的引用。

这会让用户将返回的对象传递给其他函数,而不知道它属于哪个子类。

这种情况下的问题将成为内存管理问题之一——选择哪个函数分配返回的对象,哪个函数删除它,以及何时删除它,这样我们就可以避免内存泄漏。


0
投票

答案很简单,只需声明函数返回 void* 类型,并在定义中返回对不同类型变量的引用即可。例如在标头 (.h) 中声明

void* RetrieveValue(string dataString1);

在定义(.cpp)中只需写

void* RetrieveValue(string dataString1)
{
    if(dataString1.size()<9)
    {
        static double value1=(double)dataString1.size();
        return &value1;
    }
    else
    {
        static string value2=dataString1+"some string";
        return &value2;
    }
}

然后在调用 RetrieveValue 的代码中将其转换为正确的值

string str;
string str_value;
double dbl_value;
if(is_string)
{
    str_value=*static_cast<*string>(RetrieveValue(str));
}
else
{
    dbl_value=*static_cast<*double>(RetrieveValue(str));
}

0
投票

您可以使用完整的模板专业化:

https://en.cppreference.com/w/cpp/language/template_specialization


-2
投票

由于您使用的示例并不是您真正想要的,所以您让每个人都有点失望。

您真正拥有的设置(使用该函数的返回值来调用其返回类型未知的函数)将不起作用,因为函数调用是在编译时解析的。

然后您就只能使用运行时解决方案。我推荐访问者模式,您必须大幅更改您的设计才能实现此更改。我确实没有其他方法可以做到这一点。

© www.soinside.com 2019 - 2024. All rights reserved.