13

我需要找到某种方法来模拟 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 也只能有一种返回类型。但我需要这样的东西。

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

4

10 回答 10

29

你必须从这个开始:

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

要支持此功能,您必须多做一些工作,以便将 value 转换为 type 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);

这就是你想要的,对吧?

于 2013-02-12T19:29:29.157 回答
2

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

 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);
于 2013-02-12T19:33:32.733 回答
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);
于 2013-02-12T19:37:17.353 回答
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
于 2013-02-12T22:30:11.997 回答
1

如果您知道您的值永远不会是零或负值,只需返回一个包含 int 的结构,然后将不需要的值加倍并归零...

这是一种廉价而肮脏,但简单的方法......

struct MyStruct{
int myInt;
double myDouble;
};

MyStruct MyFunction(){
}
于 2013-02-12T19:31:19.160 回答
0

不幸的是,没有办法重载函数返回类型看到这个答案 通过返回类型重载

于 2013-02-12T19:30:31.877 回答
0
int a=itoa(retrieveValue(dataString));
double a=ftoa(retrieveValue(dataString));

两者都返回一个字符串。

于 2013-02-12T19:30:38.800 回答
0

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

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

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

于 2013-02-12T19:31:45.450 回答
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));
}
于 2020-11-08T22:50:21.327 回答
-2

由于您使用了一个并非您真正想要的示例,因此您让每个人都有些失望。

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

然后,您将被限制为运行时解决方案。我推荐访问者模式,你必须大幅改变你的设计以允许这种改变。我真的没有其他方法可以做到这一点。

于 2013-02-12T19:54:20.107 回答