2010-12-03 4 views
2

У меня есть макрос:Как заменить макрос на функцию шаблона?

#define TWO_CMD(c1, c2) { const long r1=c1; if (r1) return r1; return c2; } 

и использование:

long MyClass::SomeFunc(long a) 
{ 
    //... 
    if (a) 
     TWO_CMD(Func<int>(a), Func<void>()); 
    else 
     TWO_CMD(Func<double>(), Func<std::string>(a)); 
    //... 
} 

Func является функцией-членов шаблона. Но главное требование - сохранить читаемость кода!

Я предполагаю, что есть вариант с функцией члена шаблона, который имеет указатель на функцию-членов в качестве аргументов:

return two_cmd(Func<int>, a, Func<void>); 

Но этот синтаксис не ясно.

+1

Сохраняйте читаемость кода !!! Теперь он не читается. – 2010-12-03 07:49:42

ответ

4

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

Самый простой способ сделать это, чтобы передать вызываемые объекты шаблона функции и его возвращают результат:

template <typename R, typename F, typename G> 
R Evaluate(const F& f, const G& g) { 
    R x = f(); 
    return x ? x : g(); 
} 

Используется как:

return Evaluate<long>(
    std::bind(&MyClass::Func<int>, this, a), 
    std::bind(&MyClass::Func<void>, this)); 

return Evaluate<long>(
    std::bind(&MyClass::Func<double>, this), 
    std::bind(&MyClass::Func<std::string>, this, a)); 

Если ваш компилятор и стандартная библиотека делать не поддерживает C++ 0x или C++ TR1 bind, существует реализация в Boost, которая почти идентична.

(я назвал функцию Evaluate, потому что я не могу думать о хорошем имени для этой функции.)

+0

К сожалению, эту версию трудно прочитать (со связыванием, &, этим и т. Д.). – 2010-12-03 07:13:39

+2

@simply_to_ask: Как и все остальные C++, этот синтаксис довольно прост, если вы его использовали некоторое время. Да, для этого нужно привыкнуть, но используемые здесь инструменты неоценимы. – 2010-12-03 07:16:38

2

Эмм, конечно, это довольно тривиальным? В чем смысл усложнения? Я думаю, что код ниже достаточно прост для понимания - зачем его скрывать?

long res = 0; 
if (a) 
    return (res = Func<int>(a)) ? res : Func<void>(); 
else 
    return (res = Func<double>()) ? res : Func<std::string>(a); 

К сожалению, были дополнительные () из ранее != 0 теста

0

Мой ответ не непосредственно решения вопроса, но только некоторые наблюдения:

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

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

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

  3. В вашем примере, если a равно 0 (единственное значение, дающее false в выражении), Func<std::string>(a) является [потенциально] константой.

Смежные вопросы