LINUX.ORG.RU

Шаблоны С++


0

0

Всем привет!

Начал вот писать класс для работы с командной строкой.
За основу взял boost::program_options.

Есть у меня в программе строковые и булевые опции.
Для их хранения предусмотрены ассоциативные массивы.

Только вот не хочу я делать методы типа
GetStringOption, GetBoolOption и т.д.
Хочется написать что-то вроде шаблонного метода, приведённого
ниже, а потом вызывать:

CmdLine C(argc,argv);
const std::string s("disable_stderr");
bool b = C.GetOpt(s);
const std::string ss("cfg_f_name");
std::string name = C.GetOpt(ss);

Правда вот для C++ подобные фокусы неправильны.
Как я понимаю без явной специализации не обойтись:
bool b = C.GetOpt<bool>(s);
std::string name = C.GetOpt<std::string>(ss);

Вообщем задача понятна : вызывать нужный метод в зависимости от
типа значения слева без явного указания этого типа.
Как это реализовать в C++?

Кусочек класса приведён ниже
/*
  \class CmdLine
  \brief Class for encapsulate all command line operations
*/
class CmdLine
{
   public:
     /// Constructor
     CmdLine(int argc, char** argv);
     /// Destructor
     ~CmdLine();
     template <class T>
     T GetOpt(const std::string& OptionName) const
     {
        // Do anything 
     }
   private:
     /// Map for string options, e.g. Script File Name
     std::map<std::string,std::string> StringOptions_;
     /// Map for string options, e.g. Disable StdErr Output
     std::map<std::string,bool> BoolOptions_;
     /// Options Description
     po::options_description Description_;
};

Вот так не ?

template <typename A> void get(string& s, A& x) { .... }

...

bool x; int y; string z;

...

get("x",x); get("y",y); get("z",z);

anonymous
()
Ответ на: комментарий от anonymous

Здесь шаблонный параметр в списке параметров функции get, а у меня
он только в возвращаемом значении!

Как я понимаю разница очень большая!

Или я не прав?

Krivenok_Dmitry
() автор топика
Ответ на: комментарий от Krivenok_Dmitry

С точки зрения красовты оформления кода строчка a = get ("a") смотрится, но реализовать такое только средствами шаблонов достаточно трудоемко (может в бусте есть такой наворот - хз). Проще get("a",a), где а передается в функцию по ссылке

anonymous
()
Ответ на: комментарий от anonymous

> Проще get("a",a), где а передается в функцию по ссылке
Это решение мне известно.

> достаточно трудоемко
А в принципе возможно?

Krivenok_Dmitry
() автор топика
Ответ на: комментарий от anonymous

На ум приходит еще один вариант - с неявным преведением типов, однако у него есть существенный недостаток - трудно реализовать контроль типов в исключительно в компайл тайм, придестя немного в рантайм залезть

anonymous
()
Ответ на: комментарий от Krivenok_Dmitry

Вприницпе исключительно в компайл тайм именно тем способом которым ты хочешь это невозможно. Неявное указание параметров шаблонов работает только с аргументами функции но не с ее значениями. При помощи ряда изварщенных методов с использованием рантайма это возможно. Только смысл ? Ради того чтобы в некоторых местах написать вместо get("a",a); a = get ("a") ? Овчинка выделки не стоит.

anonymous
()
Ответ на: комментарий от anonymous

s/c ее значениями/с ее возвращаемыми значениями

anonymous
()
Ответ на: комментарий от anonymous

Вот например один из варантов геморойного способа в котором может
 глючить приведение типов

#include <iostream>
#include <string> 

using namespace std;

struct Property { // Тут красиво надо через union. Лень ! 
#define Property(x) x _##x; Property(x __##x): _##x(__##x) {} \
operator x () { cerr<<"Приведение типа к  "<<#x<<endl; return _##x; }
      Property(int);
      Property(bool);
      Property(string);
#undef Property
};

inline Property get (string s) {

    switch (s[0]) 
    {
	case 'a' : return "a"; 
	case 'b' : return 1;
	case 'c' : return true;     
	default  : return 2;
    }
} 

int main() 
{
    string a = get("a");
    int    b = get("b");
    bool   c = get("c");
    int    d = get("e");
} 

anonymous
()
Ответ на: комментарий от romanSA

Шаблонный variant реализованный в компайлтайм для такой задачи непрокатит, а рантайм variant и есть union с определенными наворотами.

anonymous
()

Читайте Страструпа, млин......

Низя никак. Вы чего????

Речь идет о перегрузке  функций (так по мойму называется. склероз у меня). Эта мня работает токо по типу аргумента (как это сделать, через шаблон или руками дело десятое), но никак не по типу возвращаемого значения. Как по вашему компайлер различит string f(string) и bool f(string)????

То что моно сделать (могу слажать, так как с С++ давно не возякался):

class CmdLine{
...
temlate <class T> T GetOpt(const string&);
...
};

использование: a=C.GetOpt<bool>(s);

ну или делаешь общий виртуальный базовый класс, наследуешь его для каждого типа (моно через шаблон), getopt возвращает прального наследника а дальше работает преведение типов (надо определить для наследника). Тогда моно обойтись без <bool>, но реализация неск сложнее и ошибки будет тяжелее ловить.

AIv ★★★★★
()
Ответ на: Читайте Страструпа, млин...... от AIv

>Как по вашему компайлер различит string f(string) и bool f(string)????

Я не специалист по компиляторам, но на мой взгляд вызов
bool b = C.GetOpt("OptName");
даёт исчерпывающую информацию.

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

Судите сами: 
1) Имеем класс
2) У класса есть шаблонный метод (известно, что параметр шаблона
используется только в качестве возвращаемого значения)
3) Есть совершенно однозначный (в смысле контекста) вызов данного 
метода. Т.е. тип возвращаемого значения известен (в примере bool)

Почему бы тогда не дать подобную возможность.
Вероятно исключительно из-за проблем в реализации?

Вообщем всё сказанное - в комитет по стандартизации :))

При разрешении перегрузки тип возвр. значения не используется,
это факт.

Интересно, эквивалентны ли несколько перегруженных функции нескольким
"инстацированным копиям" фаблонной функции с точки зрения разрешения
перегрузок?

Надо действительно посмотреть Страуструпа и Вандервулда.
 

Krivenok_Dmitry
() автор топика
Ответ на: комментарий от Krivenok_Dmitry

ну батенька.... такого по моему нигде, даже в окамле нету. А как вы будете разрешать что нить типа int i = C.Getopt('a')+C.getopt('b') ??? операторы выполняются последовательно, сначала вызов ф-ии, потом присваивание, и вызов ф-ии ничего не знает о аргументах присваиния.

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

С тз перегрузки в первом приближении пофигу шаблон или ручной метод. но если задать одноименный шаблонный и ручной методы - не знаю что будет... вообще раскрутка шаблонов была когда то сильно компайло-зависимой штукой. напр вирт. перегрушенные шаблонные методы не работали толком. как сейчас не знаю....

AIv ★★★★★
()
Ответ на: комментарий от AIv

"Ручной" метод при разрешении имен имеет приоритет. Если ни один ручной не подойдет, то будет искаться подходящий шаблонный.

anonymous
()
Ответ на: комментарий от Krivenok_Dmitry

>Почему бы тогда не дать подобную возможность.
>Вероятно исключительно из-за проблем в реализации?

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

Пусть у нас будет только два варианта GetOpt

unsigned char GetOpt(const std::string &);
int GetOpt(const std::string &);

То как тогда выбрать подходящий вызов для вот такой конструкии:
bool b = GetOpt("optName");

А если будет еще вариант GetOpt возвращающий объект какого-то класса который умеет неявно преобразовываться к другому классу а тот в свою очередь к bool - тогда вобще труба.

Vinick ★★
()
Ответ на: комментарий от Vinick

Не по этому.

Вот, например :

int foo( int a) {...} int foo( unsigned int a) {...}

int main() { bool x = true;

foo(x);

}

Все нормально приводится. Без всяких заморочек. Один из товарищей достаточно грамотно объяснил почему нет переопределения функции по типу возвращаемого значения - потому как непонятно с какого конца распутывать, например, такие программы

int foo(); float foo(); string foo();

void bar(int); void bar(float); void bar(string);

... bar(foo()+foo()); ...

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.