Как можно написать функцию С++, которая при определенных условиях возвращает значения разных типов?

Рейтинг: 0Ответов: 3Опубликовано: 09.04.2023

Как можно написать функцию С++, которая при определенных условиях возвращает значения разных типов?

Ответы

▲ 1

C++ это строго типизированный язык, и функция возвращает только тот тип, что указан в сигнатуре (объявлении функции) Хотя можно возвращать указатель на пустой тип void* и на свой страх и риск конвертировать в нужный тип, либо использовать возможности наследования, и переопределять возвращаемый тип функции в дочерних классах. Но все таки это будут разные функции с одним названием, а не одна и та же функция

▲ 0

Не до конца понял вопрос, можно сделать через шаблоны вот так:

#include <iostream>
using namespace std;

template<typename Type>
Type func(Type a){
    return a;
}

int main(){
    cout<<func<int>(5)<<endl;
    cout<<func<char>(5)<<endl;
    cout<<func<double>(5)<<endl;
}

Либо через C макросы, но это плохая идея так как дико ненадежно:

#include <iostream>

using namespace std;

char f() { return 5; }

int main()
{
  #define fi(...) ((int)f(__VA_ARGS__))
    //fi - макрос, (int) тип функции f, __VA_ARGS__ - макрос для аргументов, но нужно занести хотя бы один
  #define fd(...) ((double)f(__VA_ARGS__))
  #define fc(...) ((char)f(__VA_ARGS__))
    

  cout << fi() << endl;
  cout << fd() << endl;
  cout << fc() << endl;

  return 0;
}
▲ 0

Возвращаемы тип менять нельзя. Но можно в один тип вместить много разных с помощью union.
Чтобы тип возвращаемого значения было просто определить можно возвращать структуру с номером типа и значение типа union которое может в себе вместить все возможные типы.
Вот пример из трёх типов : число, Си строка, C++ объект класса string

# include <string>
# include <cstring>
# include <iostream>

struct Ret {
  enum Ty { Int , Stri , stdStri } ;
  Ty t ;
  union {
    int i ;
    char * st ;
    std :: string ss ;
  } ;
  Ret():t{Int}{}
  Ret(Ret const & );
  Ret & operator = ( Ret const & ) ;
  ~Ret();
private :
  void Free ( ) ;
} ;

Ret fun ( Ret const & ) ;

int main ( ) {
  Ret i ;
  i . t = Ret :: Ty :: Int ;
  i . i = 7 ;
  Ret ri = fun ( i ) ;
  if ( ri . t == Ret :: Ty :: Int ) {
    std :: cout << "r . i = " << ri . i << std :: endl ;
  }
  Ret s ;
  s . t = Ret :: Ty :: Stri ;
  { char const * const s0 = "def" ;
    size_t const l = strlen ( s0 ) ;
    s . st = new char [ l + 1 ] ;
    strncpy ( s . st , s0 , l + 1 ) ;
  }
  Ret rs = fun ( s ) ;
  if ( rs . t == Ret :: Ty :: Stri ) {
    std :: cout << "rs . st = `" << rs . st << "`" << std :: endl ;
  }
  Ret x ;
  x . t = Ret :: Ty :: stdStri ;
  new ( & x . ss ) std :: string ( "abc" ) ;
  Ret r = fun ( x ) ;
  if ( r . t == Ret :: Ty :: stdStri ) {
    std :: cout << "r . ss = `" << r . ss << "`" << std :: endl ;
  }
}

Ret fun ( Ret const & r ) {
  Ret re { r } ;
  switch ( r . t ) {
  case Ret :: Ty :: Int :
    re . i = r . i + 1 ;
    break ;
  case Ret :: Ty :: Stri :
    { char * i ;
      for ( i = re . st ; * i ; ++ i )
        * i = toupper ( * i ) ;
      * i = '\00' ;
    }
    break ;
  case Ret :: Ty :: stdStri :
    for (auto & c: re . ss)
      c = toupper(c);  
    break ;
  } 
  return re ; 
}

Ret::  Ret(Ret const & x):t{Int}{
  ( * this ) = x ;
}

Ret & Ret :: operator = ( Ret const & x ) {
  Free ( ) ;
  t = x . t ;
  switch ( x . t ) {
  case Int :
    i = x . i ;
    break ;
  case Stri :
    { size_t const l = strlen ( x . st ) ;
      st = new char [ l + 1 ] ;
      strncpy ( st , x . st , l + 1 ) ;
    }
    break ;
  case stdStri :
    new ( & ss ) std :: string ( x . ss  ) ;
    break ;
  }
  return * this ;
}

Ret::  ~Ret(){
  Free ( ) ;
}

void Ret :: Free ( ) {
  switch ( t ) {
  case Int :
    break ;
  case Stri :
    delete [ ] st ;
    break ;
  case stdStri :
    ss . ~ basic_string ( ) ;
    break ;
  }
  t = Int ;
}