Function capable of returning different types?

I am trying to create a function in C ++, I am wondering if I can create it in such a way that it can return different types of vectors. for example, based on another case, it returns a vector string, int, double, or ... whatever. Is this possible in C ++? (I don’t want to use the overload function with different arg (S) arguments and different return values) I am very new to C ++ and my question may seem silly.

here is a snippet of my code:

// zero here means intersection

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

// here I want to return a "point" or "line with its points" or at the top level of our surface. // I want to do everything in one function! }

+6
source share
3 answers

Patterns

Try the following:

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

You can call this function with a different type this way:

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

Alternatives

This is one way if you know the types at compile time. If you do not know the type at compile time, but only at runtime, you have different options:

  • Use unions . I can only recommend this if you have very simple C-struct types called POD (plain old data) in the C ++ standard.
  • Use some option. For example, boost::variant from the Boost libraries or QVariant from the Qt library. They are safe types of unions for more general types. They also allow some conversion between different types. For example, setting something to an integer value, you can read the same value as a floating point number.
  • Use boost::any , which can wrap any type, but does not allow conversion between them.
  • Use inheritance and polymorphism. For this case, you need a common base class, say Base . Then you create an array of pointers to this base, preferably using std::shared_ptrs . Thus, the array type will be std::vector<std::shared_ptr<Base>> . std::shared_ptr better than the built-in pointer in this case, because automatic memory management by reference counting.
  • Use a dynamic language that does not care about types and performance.
+13
source

You can use templates if you know which type will be returned before you call the function. But you cannot have a function that internally decides to return some type.

What you can do is create a class that will be a container for the returned data, fill the object of this class with the desired data, and then return this object.

 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; } 
+2
source

It depends on what you are trying to accomplish, but there are many possibilities for this. Here are some of them that come to mind:

If one of the defined list of return types is defined inside the function:

Since you edited your question, this looks like what you want. You can try 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 } 

If the return type depends on the template argument:

You can use SFINAE to control overload resolution:

 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() {...} 

If the return type can be any:

A boost::any will work fine:

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

If the return type is always inferred from a particular class:

Returns a smart pointer to the base class:

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

Source: https://habr.com/ru/post/949445/


All Articles