【问题标题】:function which is able to return different types?能够返回不同类型的函数?
【发布时间】:2013-07-15 07:46:03
【问题描述】:

我正在尝试在 C++ 中创建一个函数,我想知道我是否可以创建它以便它能够返回不同类型的向量。例如,根据不同的大小写,它返回向量字符串、int、double 或...任何东西。 在 C++ 中可以吗? (我不想使用具有不同 arg(S) 和不同返回值的重载函数) 我对 C++ 很陌生,我的问题似乎很愚蠢。

这是我的一段代码:

//这里的零表示交集

std::vector<??????> findZeros(const mesh::Region& s, char *model) const
{
//Point  
  if( model == "point" )
  {
    std::vector<Vertex> zeros;
    for(Region::pointIterator it = s.beginPoint(); itv != s.endPoint(); ++itv )
    {
      if( abs(Val(*it)) < 1.e-12 )      
      zeros.push_back(*it);
    }
    std::vector<point> zerosP(zeros.begin(), zeros.end());
    return zerosP;
  }
 //line
  else if (EntityS == "line")
  {
    std::vector<line> zerosE;
    std::vector<Point&> PointE;
    for(Region::lineIterator ite = s.beginLine(); ite != s.endLine(); ++ite )
    {
      Line ed = *ite;
        Point P0 = ed.point(0);
        Point P1 = e.point(1);
        if( ......... ) zerosE.push_back(ed);
        else if ( ....... )
        {
         PontE.push_back( P0, P1);
         zerosE.push_back(ed);
        }
      }

//这里我想返回“点”或“带有点的线”或在我们的表面上层。 //我想在一个功能中完成所有事情! }

【问题讨论】:

  • 模板 [....]
  • 是的,模板函数是你的朋友。这是一个快速指南:cplusplus.com/doc/tutorial/templates
  • 你到底需要做什么?
  • @LuchianGrigore & Mert 好吧,当然,前提是要在编译时决定。
  • 永远不要将 C 字符串与 == 进行比较。使用strncmp,或者更简单的std::string

标签: c++


【解决方案1】:

模板

试试这个:

template <typename T>
std::vector<T> func( /* arguments */ )
{
    std::vector<T> v;
    // ... do some stuff to the vector ...
    return v;
}

你可以通过这种方式调用不同类型的函数:

std::vector<int> func<int>( args );
std::vector<double> func<double>( args );

替代方案

如果您在编译时知道类型,这是一种方法。如果您在编译时不知道类型,而只在运行时知道,那么您有不同的选择:

  1. 使用unions。如果您有非常简单的类似 C 结构的类型,在 C++ 标准中称为 POD(普通旧数据),我只能推荐这个。
  2. 使用某种类型的变体。例如,Boost 库中的 boost::variant 或 Qt 库中的 QVariant。它们是更通用类型上的一种安全联合。它们还允许在不同类型之间进行一些转换。例如,将某些内容设置为整数值将可以读取与浮点数相同的值。
  3. 使用boost::any,它可以包装任何类型,但不允许在它们之间进行转换。
  4. 使用继承和多态。对于这种情况,您需要一个公共基类,例如Base。然后,您最好使用std::shared_ptrs 创建一个指向该基的指针数组。所以数组类型是std::vector&lt;std::shared_ptr&lt;Base&gt;&gt;。在这种情况下,std::shared_ptr 比内置指针更好,因为它通过引用计数自动管理您的内存。
  5. 使用不关心类型和性能的动态语言。

【讨论】:

  • 你必须去更新它,以包括我在发布答案之前准备的大部分可能性:p 仍然 +1。
【解决方案2】:

C++17 更新

如果您在编译时知道类型,则可以使用this answer 中所示的模板。

如果该类型仅在运行时已知,则使用c++17 作为boost::variant 的替代品,我们有std::variant

这是一个工作示例:

#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

using variant_vector = std::variant<std::vector<int>, std::vector<std::string>>;

auto get_vector(int i)
{
    if (i < 0)
        return variant_vector(std::vector<int>(3, 1));
    else
        return variant_vector(std::vector<std::string>(3, "hello"));
}

int main()
{
    auto visit_vec = [](const auto& vec) {
        using vec_type = typename std::remove_reference_t<decltype(vec)>::value_type;
        if constexpr (std::is_same_v<vec_type, int>)
            std::cout << "vector of int:" << std::endl;
        else if constexpr (std::is_same_v<vec_type, std::string>)
            std::cout << "vector of string:" << std::endl;
        for (const auto& x : vec)
            std::cout << x << std::endl;
    };
    
    std::visit(visit_vec, get_vector(-1));
    std::visit(visit_vec, get_vector(1));

    return 0;
}

live on Coliru

在上面的代码中,函数get_vector 返回一个std::variant 对象,该对象或者是一个std::vector&lt;int&gt; 或者一个std::vector&lt;std::string&gt;。使用std::visit 检查返回对象的内容。

【讨论】:

    【解决方案3】:

    这完全取决于您要完成的工作,但如何做到这一点有多种可能性。以下是我想到的一些:

    如果在函数内部确定了特定的返回类型列表之一:

    由于您编辑了问题,这似乎就是您想要的。你可以试试boost::variant:

    boost::variant<int, double, std::string> foo() {
        if (something) 
            //set type to int
        else if (something else)
            //set type to double
        else
            //set type to std::string
    }
    

    如果返回类型取决于模板参数:

    您可以使用 SFINAE 来操作重载解析:

    template<typename T, typename = typename std::enable_if<std::is_integral<T>::value, T>::type>
    std::vector<int> foo() {...}
    
    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
    std::vector<std::string> foo() {...}
    

    如果返回类型可以是任何东西:

    boost::any 会很好用:

    boost::any foo() {...}
    

    如果返回类型始终派生自特定类:

    返回一个指向基类的智能指针:

    std::unique_ptr<Base> foo() {
        if (something)
            return std::unique_ptr<Base>{new Derived1};
        if (something else) 
            return std::unique_ptr<Base>{new Derived2};
    }
    

    【讨论】:

    • 我尝试使用 boost::variant,但收到以下错误:没有匹配函数调用'boost::detail::variant::make_initializer_node
    • @user2090491,我不能说我自己需要它,但 Boost 文档将是一个很好的起点。至于向量,它应该可以很好地使其包含变体,可以是任何定义的类型,但是将它们全部设置为相同的类型并保持不变。
    【解决方案4】:

    如果您在调用函数之前知道要返回什么类型,则可以使用模板。但是你不能有一个内部决定返回某种类型的函数。

    你可以做的是创建一个类作为返回数据的容器,用需要的数据填充这个类的对象,然后返回这个对象。

    typedef enum { VSTRING, VINT, V_WHATEVER ... } datatype;
    
    class MyReturnClass {
    
        datatype d;
    
        // now either
        vector<string> * vs;
        vector<int> * vi;
    
        // or
        void * vector;      
    
     }
    
     MyReturnClass * thisIsTheFunction () {
    
           MyReturnClass * return_me = new MyReturnClass();
    
           return_me->datatype = VSTRING;
           return_me->vs = new Vector<String>;
    
           return return_me;
    
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多