Установка network-manager-openvpn-gnome
от Центра программного обеспечения Ubuntu (обычно это скрыто от результатов поиска при поиске openvpn, если Вы не нажимаете "Show XX technical items" у основания окна).
Или может использовать терминал ( Ctrl + Высокий звук + T ):
sudo aptitude install network-manager-openvpn-gnome
После этого опция соединиться с openvpn VPN появится под
администратор сети->, соединения VPN-> настраивают vpn
Вы можете использовать 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 может также сообщить, какие части Повышение вашего кода зависит от и какие лицензии используют те зависимости.
C ++ - это язык со строгой типизацией и не имеет понятия неизвестного типа. Вы можете попробовать использовать boost :: any, который может (вроде как) указывать любой тип. Однако я бы поставил под сомнение структуру вашей функции.
Если вы знаете тип во время компиляции, вы можете использовать шаблоны. Если тип зависит от времени выполнения, то использование шаблонов не вариант.
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;
}
Используйте 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);
}
}
Обычный способ для достижения чего-то подобного используется 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 ++.
Вы можете использовать структуру, содержащую void *
, указывающую на значение, которое вы хотите вернуть вместе с size_t
, который указывает размер возвращаемого объекта. Примерно так:
struct Something {
void *value;
size_t size;
};
Помните, что void *
должен указывать на значение, находящееся в куче (т. Е. Динамически выделяемое с использованием new
или malloc
) и вызывающий должен позаботиться об освобождении выделенного объекта.
Сказав это, я думаю, что в целом это плохая идея.
Изменить: Вы также можете рассмотреть возможность включения флага, указывающего, что было возвращено в приведенной выше структуре так что вызывающий может понять это, если вызывающий не знает, какого типа ожидать.
Вы можете использовать объединение:
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;
}
РЕДАКТИРОВАТЬ: boost :: any с использованием bcp (спасибо AraK) кажется лучшим решением на сегодняшний день, но можно ли доказать (в некоторой степени), что для этого не существует решения ANSI C ++ проблема?
Кажется, вы немного запутались в терминологии здесь.
Во-первых, давайте назовем это ISO C ++, не так ли? Он был стандартизирован ISO в 1998 году, и с тех пор именно на него ссылаются, когда говорят о «стандартном C ++». Что вы подразумеваете под «решением ANSI C ++»?
Я не могу представить, что это за » доказательство "вы бы искали. C ++ - это документ в форме прозы. Это не математическое уравнение. Его нельзя" доказать ", кроме как" t в принципе невозможно - кроме перечисления каждого отдельного предложения стандарта и документального подтверждения того, что ни одно из них не описывает то, что вы ищете. И я сомневаюсь, что вы найдете кого-нибудь, кто захочет сделать то для вас.
В любом случае, правильное стандартное решение C ++ - это для использования Boost. t в принципе невозможно - кроме перечисления каждого отдельного предложения стандарта и документального подтверждения того, что ни одно из них не описывает то, что вы ищете. И я сомневаюсь, что вы найдете кого-нибудь, кто захочет сделать то для вас.
В любом случае, правильное стандартное решение C ++ - это для использования Boost. Это не тяжелое решение. Boost довольно легковесен, поскольку вы можете включать ровно нужных вам битов без каких-либо зависимостей от остальной части коллекции библиотеки.
Из того, что вы описали (легкое приложение для широкой базы пользователей ) нет причин не использовать Boost. Это может упростить ваш код и уменьшить количество ошибок, вызванных попытками изобрести колесо. При распространении скомпилированного исполняемого файла он не требует затрат. Библиотека Boost.Any
, как и большая часть Boost, предназначена только для заголовков и просто компилируется в ваш исполняемый файл. Нет необходимости распространять отдельные библиотеки.
Нет ничего, что можно было бы получить, пытаясь изобрести колесо. Ваш исполняемый файл не будет меньше или более эффективным, но он будет более глючным.
И я ' Я готов поспорить, что ваше самодельное решение не будет соответствовать стандарту ANSI C ++. Он будет полагаться на некоторую форму неопределенного поведения. Если вам нужно решение ANSI-C ++, лучше всего будет Boost.
В библиотеках исходного кода Adobe также есть adobe :: any_regular_t
, который позволяет хранить любой тип, если он моделирует концепцию Regular . Вы бы обернули возвращаемое значение так же, как и с boost :: any
. (На связанной странице также есть документация о том, чем adobe :: any_regular_t
отличается от boost :: any
- конечно, выбранный вами тип должен зависеть от требований вашего кода. .)
Вместо этого вы можете передать по ссылке и сохранить типы и проверить, работает ли он в то же время, без дополнительных библиотек (ваш тип решения 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;
}
.. .
Я часто считаю это решение более чистым с точки зрения дизайна. К сожалению, сигнатуры функций не позволяют использовать несколько типов в качестве возвращаемых типов, но таким образом вы можете передать что угодно.
Если пользователь знает, что вставлено, вы можете использовать шаблон, чтобы исправить это. Если нет, я не могу придумать никакого решения.
Я думаю, что проблема в дизайне этой функции. Вы пробовали перегрузить?
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 вы можете разместить больше кода и заставить их вызывать другие функции, чтобы код не повторялся.
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;
}
}