简体   繁体   English

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

[英]C++ same function parameters with different return type

I need to find some way to mock an overload of a function return type in C++.我需要找到某种方法来模拟 C++ 中函数返回类型的重载。

I know that there isn't a way to do that directly, but I'm hoping there's some out-of-the-box way around it.我知道没有办法直接做到这一点,但我希望有一些开箱即用的方法。 We're creating an API for users to work under, and they'll be passing in a data string that retrieves a value based on the string information.我们正在创建一个供用户使用的 API,他们将传入一个数据字符串,该字符串根据字符串信息检索一个值。 Those values are different types.这些值是不同的类型。 In essence, we would like to let them do:本质上,我们想让他们做:

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

But that doesn't work in C++ (obviously).但这在 C++ 中不起作用(显然)。 Right now, we're having it set up so that they call:现在,我们正在设置它,以便他们调用:

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

However, we don't want them to need to know what the type of their data string is.但是,我们不希望他们需要知道他们的数据字符串的类型是什么。

Unfortunately, we're not allowed to use external libraries, so no using Boost.不幸的是,我们不允许使用外部库,所以没有使用 Boost。

Are there any ways we can get around this?有什么办法可以解决这个问题吗?

Just to clarify, I understand that C++ can't natively do it.澄清一下,我知道 C++ 本身无法做到这一点。 But there must be some way to get around it.但必须有办法绕过它。 For example, I thought about doing RetrieveValue(dataString1, GetType(dataString1)).例如,我想过做 RetrieveValue(dataString1, GetType(dataString1))。 That doesn't really fix anything, because GetType also can only have one return type.这并不能真正解决任何问题,因为 GetType 也只能有一种返回类型。 But I need something like that.但我需要这样的东西。

I understand that this question has been asked before, but in a different sense.我知道以前有人问过这个问题,但意义不同。 I can't use any of the obvious answers.我不能使用任何明显的答案。 I need something completely out-of-the-box for it to be useful to me, which was not the case with any of the answers in the other question asked.我需要一些完全开箱即用的东西才能对我有用,而其他问题中的任何答案都不是这种情况。

You've to start with this:你必须从这个开始:

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

To support this function, you've to work a bit more, in order to convert the value into the type T .要支持此功能,您需要做更多工作,以便将值转换为T类型。 One easy way to convert value could be this:转换值的一种简单方法可能是:

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");
}

Note that you still have to call this function as:请注意,您仍然必须将此函数调用为:

int x = RetrieveValue<int>(key);

You could avoid mentioning int twice, if you could do this instead:如果你可以这样做,你可以避免两次提及int

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

where Value is implemented as:其中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");
    }
}

Then you could write this:那么你可以这样写:

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

which is which you want, right?哪个是你想要的,对吧?

The only sane way to do this is to move the return value to the parameters.唯一明智的方法是将返回值移动到参数中。

 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);

Whether it is an overload or a specialization, you'll need the information to be in the function signature.无论是重载还是特化,您都需要函数签名中的信息。 You could pass the variable in as an unused 2nd argument:您可以将变量作为未使用的第二个参数传入:

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);

If you know your value can never be something like zero or negative, just return a struct holding int and double and zero out the one you don't need...如果您知道您的值永远不会是零或负数,只需返回一个包含 int 和 double 的结构体,然后将您不需要的值归零...

It's a cheap and dirty, but easy way...这是一种既便宜又脏,但简单的方法......

struct MyStruct{
int myInt;
double myDouble;
};

MyStruct MyFunction(){
}

If the datastrings are compile-time constants (as said in answering my comment), you could use some template magic to do the job.如果数据字符串是编译时常量(如在回答我的评论中所说),您可以使用一些模板魔术来完成这项工作。 An even simpler option is to not use strings at all but some data types which allow you then to overload on argument.一个更简单的选择是根本不使用字符串,而是使用一些允许您重载参数的数据类型。

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

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

int a=itoa(retrieveValue(dataString));
double a=ftoa(retrieveValue(dataString));

both return a string.都返回一个字符串。

As an alternative to the template solution, you can have the function return a reference or a pointer to a class, then create subclasses of that class to contain the different data types that you'd like to return.作为模板解决方案的替代方案,您可以让函数返回一个类的引用或指针,然后创建该类的子类以包含您想要返回的不同数据类型。 RetrieveValue would then return a reference to the appropriate subclass. RetrieveValue然后将返回对适当子类的引用。

That would then let the user pass the returned object to other functions without knowing which subclass it belonged to.这会让用户在不知道它属于哪个子类的情况下将返回的对象传递给其他函数。

The problem in this case would then become one of memory management -- choosing which function allocates the returned object and which function deletes it, and when, in such a way that we avoid memory leaks.在这种情况下,问题将成为内存管理之一——选择哪个函数分配返回的对象,哪个函数删除它,以及何时以这样的方式避免内存泄漏。

The answer is simple just declare the function returning void* type and in the definition return a reference to the variable of different types.答案很简单,只需声明返回 void* 类型的函数,并在定义中返回对不同类型变量的引用。 For instance in the header (.h) declare例如在头文件 (.h) 中声明

void* RetrieveValue(string dataString1);

And in the definition (.cpp) just write在定义 (.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;
    }
}

Then in the code calling RetrieveValue just cast to the right value然后在调用 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));
}

Since you used an example that wasn't really what you wanted, you threw everyone off a bit.由于您使用的示例并不是您真正想要的,因此您让每个人都有些失望。

The setup you really have (calling a function with the return value of this function whose return type is unknowable) will not work because function calls are resolved at compile time.您真正拥有的设置(使用返回类型未知的函数的返回值调用函数)将不起作用,因为函数调用是在编译时解析的。

You are then restricted to a runtime solution.然后,您只能使用运行时解决方案。 I recommend the visitor pattern, and you'll have to change your design substantially to allow for this change.我推荐访问者模式,您必须大幅更改您的设计以允许此更改。 There isn't really another way to do it that I can see.我真的没有其他方法可以做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM