可变函数返回类型C++

Varying function return type C++

本文关键字:C++ 返回类型 函数      更新时间:2023-10-16

那么,使用C++14中新的auto返回类型推导,有没有一种方法可以创建具有不同返回类型的函数?

例如:

auto replaceStr(string base, string search, string replace) {
  size_t found = base.find(search);
  if (found == string::npos) {
    return false; //Return this is replace is not found
  }
  else {
    base.replace(found, (found+search.length()), replace);
    return base; //Return this after the replacement
  }
}

我知道这行不通。那么,有办法让它发挥作用吗?

EDIT:评论中的大多数人都告诉我这是不可能的,因为编译器在编译时不知道函数的返回类型。那么,也许我们可以让函数有一个默认的返回类型和可选的返回类型?

C++是一种静态类型语言:在编译时无法返回未知的变量类型。

请参阅这个SO关于静态和动态类型语言差异的问题,这些差异也被称为弱类型或强类型。

关于C++14 auto返回类型,请参阅何时应使用C++14自动返回类型扣除?

正如已经指出的,编译器需要在编译时知道函数返回类型。

对于您的特定示例,您可以返回一个std::pair<bool, string>。在没有进行替换的情况下,该对的second成员被忽略。

auto res = replaceStr(base, search, replace);
if (res.first) {
    auto newBase = res.second;
    // ...
}

虽然这不能直接回答您的问题,但一种常见的方法是传递引用:

bool replaceStr(string &base, string search, string replace) {
    size_t found = base.find(search);
    if (found == string::npos) {
        return false; //Return this is replace is not found
    }
    base.replace(found, (found+search.length()), replace);
    return true;
}

然后你会像这样使用它:

if (replaceStr(base,search,replace)) {
    // it was replaced, use the modified base.
}
else {
    // it wasn't replaced
}

从那以后,评论中的大多数人都告诉我这是不可能的编译器不知道函数的返回类型汇编

编译器确实知道类型。如果编译器无法推导类型,则表示程序格式不正确,不会进行编译。auto并不意味着弱类型,它表示一种占位符类型,可以使用模板参数推导来推导。

C++不直接支持变量返回类型,但肯定可以实现。下面是一个变量返回类型的例子,在一种情况下,返回类型是在编译时选择的,在另一种情况中,返回类型则是在运行时选择的。

#include <string>
#include <memory>
#include <sstream>
#include <iostream>
// dynamically varying return type
class AnyBase
{
public:
    virtual ~AnyBase() {};
    const std::string as_string() const
    {
        return this->as_string_v();
    }

private:
    virtual const std::string as_string_v() const = 0;
};
typedef AnyBase Any;
template<typename T>
class AnyDerived : public AnyBase
{
    T* obj_ptr_;
public:
    template<typename... Args>
    AnyDerived(Args&&... args)
    {
        obj_ptr_ = new T(std::forward<Args...>(args...));
    }
    ~AnyDerived()
    {
        delete obj_ptr_;
    }
private:
    const std::string as_string_v() const;
    const char* type_string_v() const;
};
template<class T>
const std::string AnyDerived<T>::as_string_v() const
{
    std::ostringstream oss;
    oss << *obj_ptr_;
    return oss.str();
}
std::ostream& operator<<(std::ostream& os, const Any& a)
{
    os << a.as_string();
    return os;
}

std::unique_ptr<Any> foo(bool as_char)
{
    if (as_char)
        return std::unique_ptr<Any>{new AnyDerived<char>('1')};
    else
        return std::unique_ptr<Any>{new AnyDerived<int>(1)};
}

// statically varying return type
template<typename T>
T bar()
{
    return 1;
}
template<>
char bar<char>()
{
    return '1';
}

int main()
{
    bool as_char;
    as_char = true;
    const auto a1 = foo(as_char);
    as_char = false;
    const auto a2 = foo(as_char);
    const auto a3 = bar<int>();
    const auto a4 = bar<char>();
    std::cout << "*a1: " << *a1 << std::endl;
    std::cout << "*a2: " << *a2 << std::endl;
    std::cout << " a3: " <<  a3 << std::endl;
    std::cout << " a4: " <<  a4 << std::endl;
}

a1封装指向char的指针,a2封装指向int的指针,其中a3int,而a4char。正如您在main()中看到的,它可以变得相当透明。

输出:

*a1: 1
*a2: 1
 a3: 1
 a4: 1

在这种情况下,我只会抛出一个错误。

string replaceStr(string base, string search, string replace) {
  size_t found = base.find(search);
  if (found == string::npos) {
    throw MyException(); 
  }
  else {
    base.replace(found, (found+search.length()), replace);
    return base; //Return this after the replacement
  }
}

但如果你想创建一个类似工厂的函数,可以返回任何你能返回的东西:

  • 使用多态性并返回一个指向基的指针
  • 将您想要的任何内容投射到std::shared_ptr<void>
  • 使用boost::any

函数可以返回void*,它可以指向任何东西。然而,如果你不小心,这种方法可能会让你在管理内存方面遇到麻烦。