Функция, которая возвращает неизвестный тип

Установка network-manager-openvpn-gnome от Центра программного обеспечения Ubuntu (обычно это скрыто от результатов поиска при поиске openvpn, если Вы не нажимаете "Show XX technical items" у основания окна).

Или может использовать терминал ( Ctrl + Высокий звук + T ):

sudo aptitude install network-manager-openvpn-gnome

После этого опция соединиться с openvpn VPN появится под

администратор сети->, соединения VPN-> настраивают vpn

8
задан Jacob 13 December 2009 в 16:32
поделиться

13 ответов

Вы можете использовать boost :: any или boost :: variant , чтобы делать то, что вы хотите. Я рекомендую boost :: variant , потому что вы знаете набор типов, которые хотите вернуть.


Это очень простой пример, хотя вы можете сделать гораздо больше с вариантом . Посмотрите ссылку на дополнительные примеры :)

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

Вывод:

1001
3.2
V

Я бы использовал boost :: variant вместо union , потому что вы не можете использовать типы, отличные от POD внутри союза . Кроме того, boost :: any отлично подходит, если вы не знаете, с каким типом имеете дело. В противном случае я бы использовал boost :: variant , потому что это намного эффективнее и безопаснее.


Отвечая на отредактированный вопрос: Если вы не хотите отправлять Boost с вашим кодом взгляните на bcp . извлечение подмножеств Boost, это полезно для авторов Boost, которые хотят раздавать свою библиотеку отдельно от Boost, а также для пользователей Boost, которые хотите распространить подмножество Boost с их приложением.

bcp может также сообщить, какие части Повышение вашего кода зависит от и какие лицензии используют те зависимости.

25
ответ дан 5 December 2019 в 04:38
поделиться

C ++ - это язык со строгой типизацией и не имеет понятия неизвестного типа. Вы можете попробовать использовать boost :: any, который может (вроде как) указывать любой тип. Однако я бы поставил под сомнение структуру вашей функции.

8
ответ дан 5 December 2019 в 04:38
поделиться

Если вы знаете тип во время компиляции, вы можете использовать шаблоны. Если тип зависит от времени выполнения, то использование шаблонов не вариант.

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;
}
5
ответ дан 5 December 2019 в 04:38
поделиться

Используйте boost :: any :

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

    switch(a)
    {
    case 1: return boost::any(INT);
    case 2: return boost::any( FLOAT);
    case 3: return boost::any( CHAR);
    }
}
3
ответ дан 5 December 2019 в 04:38
поделиться

Обычный способ для достижения чего-то подобного используется C, который не всегда работает в C ++, с объединением и полем типа:

enum SomeType { INT, FLOAT, CHAR };
struct Something
{
    SomeType type;
    union
    {
        int i;
        float f;
        char c;
    };
};

Something DoIt(int a)
{
    Something s;
    switch (a)
    {
      case 1:
        s.type = INT;
        s.i = 2;
        break;
      case 2:
        s.type = FLOAT;
        s.f = 1.2;
        break;
      case 3:
        s.type = CHAR;
        s.c = 'a';
        break;
      default:
        // ???
    }
    return s;
}

Это не работает в C ++, когда одним из возможных типов значений является класс с не- тривиальный конструктор, потому что не всегда будет понятно, какой конструктор следует вызвать. Boost.Variant использует более сложную версию этого подхода для обеспечения такого рода конструкции для любых типов значений в C ++.

3
ответ дан 5 December 2019 в 04:38
поделиться

Вы можете использовать структуру, содержащую void * , указывающую на значение, которое вы хотите вернуть вместе с size_t , который указывает размер возвращаемого объекта. Примерно так:

struct Something {
    void *value;
    size_t size;
};

Помните, что void * должен указывать на значение, находящееся в куче (т. Е. Динамически выделяемое с использованием new или malloc ) и вызывающий должен позаботиться об освобождении выделенного объекта.

Сказав это, я думаю, что в целом это плохая идея.

Изменить: Вы также можете рассмотреть возможность включения флага, указывающего, что было возвращено в приведенной выше структуре так что вызывающий может понять это, если вызывающий не знает, какого типа ожидать.

3
ответ дан 5 December 2019 в 04:38
поделиться

Вы можете использовать объединение:

typedef union {
  int i;
  float f;
  char c;
} retType;

retType DoIt(int a){
  retType ret;

  float FLOAT = 1.2;
  int INT = 2;
  char CHAR = 'a';

  switch(a)
  {
    case 1: ret.i = INT; break;
    case 2: ret.f = FLOAT; break;
    case 3: ret.c = CHAR; break;
  }
  return ret;
}
1
ответ дан 5 December 2019 в 04:38
поделиться

РЕДАКТИРОВАТЬ: boost :: any с использованием bcp (спасибо AraK) кажется лучшим решением на сегодняшний день, но можно ли доказать (в некоторой степени), что для этого не существует решения ANSI C ++ проблема?

Кажется, вы немного запутались в терминологии здесь.

Во-первых, давайте назовем это ISO C ++, не так ли? Он был стандартизирован ISO в 1998 году, и с тех пор именно на него ссылаются, когда говорят о «стандартном C ++». Что вы подразумеваете под «решением ANSI C ++»?

  • Решение, которое компилируется чисто с использованием только ANSI (или ISO) C ++? Если это так, Boost является решением ANSI C ++
  • Решение уже реализовано в стандартной библиотеке ANSI C ++? Если да, то нет, такого решения не существует (и нет никакого «доказательства», кроме «прочтите языковой стандарт и посмотрите, сможете ли вы найти такой класс. Если вы не можете, то его там нет».
  • Решение, которое вы могли бы реализовать самостоятельно , используя только ANSI C ++. Тогда ответ будет «да, вы могли бы скопировать исходный код из Boost».

Я не могу представить, что это за » доказательство "вы бы искали. C ++ - это документ в форме прозы. Это не математическое уравнение. Его нельзя" доказать ", кроме как" t в принципе невозможно - кроме перечисления каждого отдельного предложения стандарта и документального подтверждения того, что ни одно из них не описывает то, что вы ищете. И я сомневаюсь, что вы найдете кого-нибудь, кто захочет сделать то для вас.

В любом случае, правильное стандартное решение C ++ - это для использования Boost. t в принципе невозможно - кроме перечисления каждого отдельного предложения стандарта и документального подтверждения того, что ни одно из них не описывает то, что вы ищете. И я сомневаюсь, что вы найдете кого-нибудь, кто захочет сделать то для вас.

В любом случае, правильное стандартное решение C ++ - это для использования Boost. Это не тяжелое решение. Boost довольно легковесен, поскольку вы можете включать ровно нужных вам битов без каких-либо зависимостей от остальной части коллекции библиотеки.

Из того, что вы описали (легкое приложение для широкой базы пользователей ) нет причин не использовать Boost. Это может упростить ваш код и уменьшить количество ошибок, вызванных попытками изобрести колесо. При распространении скомпилированного исполняемого файла он не требует затрат. Библиотека Boost.Any , как и большая часть Boost, предназначена только для заголовков и просто компилируется в ваш исполняемый файл. Нет необходимости распространять отдельные библиотеки.

Нет ничего, что можно было бы получить, пытаясь изобрести колесо. Ваш исполняемый файл не будет меньше или более эффективным, но он будет более глючным.

И я ' Я готов поспорить, что ваше самодельное решение не будет соответствовать стандарту ANSI C ++. Он будет полагаться на некоторую форму неопределенного поведения. Если вам нужно решение ANSI-C ++, лучше всего будет Boost.

3
ответ дан 5 December 2019 в 04:38
поделиться

В библиотеках исходного кода Adobe также есть adobe :: any_regular_t , который позволяет хранить любой тип, если он моделирует концепцию Regular . Вы бы обернули возвращаемое значение так же, как и с boost :: any . (На связанной странице также есть документация о том, чем adobe :: any_regular_t отличается от boost :: any - конечно, выбранный вами тип должен зависеть от требований вашего кода. .)

0
ответ дан 5 December 2019 в 04:38
поделиться

Вместо этого вы можете передать по ссылке и сохранить типы и проверить, работает ли он в то же время, без дополнительных библиотек (ваш тип решения ansi C ++):

bool DoIt (int i, int & r1)
{
  if (i==1) {r1 = 5; return true}
  return false;
}

bool DoIt (int i, double & r2)
{
  if (i==2) {r2 = 1.2; return true}
  return false;
}

.. .

Я часто считаю это решение более чистым с точки зрения дизайна. К сожалению, сигнатуры функций не позволяют использовать несколько типов в качестве возвращаемых типов, но таким образом вы можете передать что угодно.

0
ответ дан 5 December 2019 в 04:38
поделиться

Если пользователь знает, что вставлено, вы можете использовать шаблон, чтобы исправить это. Если нет, я не могу придумать никакого решения.

-1
ответ дан 5 December 2019 в 04:38
поделиться

Я думаю, что проблема в дизайне этой функции. Вы пробовали перегрузить?

class Test
{

public:

int DoIt(int a) {

  int INT = 2;
   return INT;

} 

float DoIt(float a) {

float FLOAT = 1.2; 
return FLOAT;

} 

char DoIt(char a) {

char CHAR = 'a'; 
return CHAR;

} 

};


int main(int argc, char* argv[])
{       
    Test obj;

//....

switch(a)
case 1: 
    cout<< obj.DoIt(1);    
break;

case 2:
cout<< obj.DoIt(1.01);   
break;

case 3:
cout<< obj.DoIt("1");   
break;

    return 0;
}

Внутри функций DoIt вы можете разместить больше кода и заставить их вызывать другие функции, чтобы код не повторялся.

-1
ответ дан 5 December 2019 в 04:38
поделиться
​​

SOMETHING = void *

Вы должны преобразовать возвращаемое значение, поэтому вы должны знать, что возвращается.

void* 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;
        }
    }
-3
ответ дан 5 December 2019 в 04:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: