Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function which returns an unknown type

class Test
{
public:

 SOMETHING DoIt(int a)
 {
  float FLOAT = 1.2;
  int INT = 2;
  char CHAR = 'a';

  switch(a)
  {
  case 1: return INT;
  case 2: return FLOAT;
  case 3: return CHAR;
  }
 }
};


int main(int argc, char* argv[])
{  
 Test obj;
 cout<<obj.DoIt(1);    
    return 0;
}

Now, using the knowledge that a = 1 implies that I need to return an integer, etc., is there anyway Doit() can return a variable of variable data type?

Essentially, with what do I replace SOMETHING ?

PS: I'm trying to find a an alternative to returning a structure/union containing these data types.

like image 227
Jacob Avatar asked Aug 31 '09 17:08

Jacob


2 Answers

If you know type at compile time you could use templates. If type depends on run-time, then using templates is not an option.

class Test
{
  template<int> struct Int2Type {};
  template<>    struct Int2Type<1> { typedef int value_type; };
  template<>    struct Int2Type<2> { typedef float value_type; };
  template<>    struct Int2Type<3> { typedef char value_type; };

public:
  template<int x> typename Int2Type<x>::value_type DoIt() {}; // error if unknown type used
  template<> typename Int2Type<1>::value_type DoIt<1>() { return 2; };
  template<> typename Int2Type<2>::value_type DoIt<2>() { return 1.2f; };
  template<> typename Int2Type<3>::value_type DoIt<3>() { return 'a'; };
};

int main()
{
  Test obj;
  cout << obj.DoIt<2>(); 
  return 0;
}
like image 111
Kirill V. Lyadvinsky Avatar answered Oct 11 '22 14:10

Kirill V. Lyadvinsky


You can use boost::any or boost::variant to do what you want. I recommend boost::variant because you know the collection of types you want to return.


This is a very simple example, though you can do much more with variant. Check the reference for more examples :)

#include "boost/variant.hpp"
#include <iostream>

typedef boost::variant<char, int, double> myvariant;

myvariant fun(int value)
{
 if(value == 0)
 {
  return 1001;
 }
 else if(value  == 1)
 {
  return 3.2;
 }
  return 'V';
}

int main()
{
 myvariant v = fun(0);
 std::cout << v << std::endl;

 v = fun(1);
 std::cout << v << std::endl;

 v = fun(54151);
 std::cout << v << std::endl;
}

The output:

1001
3.2
V

I would use boost::variant instead of a union because you can't use non-POD types inside union. Also, boost::any is great if you don't know the type you are dealing with. Otherwise, I would use boost::variant because it is much more efficient and safer.


Answering the edited question: If you don't want to ship Boost with your code, take a look at bcp. The description of bcp from the same link:

The bcp utility is a tool for extracting subsets of Boost, it's useful for Boost authors who want to distribute their library separately from Boost, and for Boost users who want to distribute a subset of Boost with their application.

bcp can also report on which parts of Boost your code is dependent on, and what licences are used by those dependencies.

like image 38
Khaled Alshaya Avatar answered Oct 11 '22 15:10

Khaled Alshaya