Возможно, это слишком просто, но что относительно того, чтобы использовать "метод извлечения", осуществляющий рефакторинг вокруг защитного пункта? Ваш пример кода этого:
public void Example()
{
if(myLogger.isLoggable(Level.INFO))
myLogger.info("A String");
if(myLogger.isLoggable(Level.FINE))
myLogger.fine("A more complicated String");
// +1 for each test and log message
}
Становится этим:
public void Example()
{
_LogInfo();
_LogFine();
// +0 for each test and log message
}
private void _LogInfo()
{
if(!myLogger.isLoggable(Level.INFO))
return;
// Do your complex argument calculations/evaluations only when needed.
}
private void _LogFine(){ /* Ditto ... */ }
Я бы просто не стал хранить указатель элемента в качестве аргумента шаблона:
template<class T, class Foo>
struct X {
X(T Foo::*p): p(p) {}
void operator()(Foo & f) {
(f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()`
}
private:
T Foo::*p;
};
template <class T, class Foo>
X<T, Foo> MakeX(T Foo::*p)
{
return p;
}
Я не думаю, что с вашим подходом возможно вывести типы: вы не можете использовать указатель -to-member передается функции, в которой происходит вывод типа.
Изменить: Однако могут быть решения на основе макросов.
Например, вы можете создать класс для создания экземпляров X, например:
template <class T, class Foo>
struct XMaker
{
template <T Foo::*p>
X<T, Foo, p> make() { return X<T, Foo, p>(); }
};
Теперь вы можете создать функцию make ... для вывода T и Foo:
template <class T, class Foo>
XMaker<T, Foo> make_x_maker(T Foo::*)
{
return XMaker<T, Foo>();
}
Что позволяет написать макрос вроде:
#define CREATE_X(member) make_x_maker(member).make<member>()
Использование:
std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r) );
У меня есть один вопрос: действительно ли вам нужно указать все эти аргументы?
struct XR
{
template <class Foo>
void operator()(Foo& foo) const { foo.r = 12 * foo.r; }
};
Это работает, нет необходимости в дополнительном методе make
, он просто работает:
void testforx()
{
std::vector<FF> cont(5);
std::for_each(cont.begin(), cont.end(), XR());
}
Я предпочитаю не быть СЛИШКОМ универсальным при создании шаблонов.
Если вы вам нужен более сложный оператор operator ()
, вы всегда можете сделать тяжелую работу ВНУТРИ этого.
Также вы можете рассмотреть Boost.Bind
,
Я не думаю, что можно уменьшить количество аргументов шаблона, которые вы должны указать, если хотите, чтобы указатель произвольной функции-члена был аргументом шаблона.
Вместо указателей на функции-члены вы можете использовать параметр обычного типа для функтора, который извлекает ссылку:
template<typename Func>
class X
{
public:
explicit X(Func f = Func()) : f(f) {}
template<class K>
void operator()(K & k) const {
f(k) = 12 * f(k);
}
private:
Func f;
};
Тогда у вас все еще есть возможность использовать специальный функтор, который напрямую обращается к определенному члену (если вы думаете, что это обеспечивает лучшую производительность), или использовать более общий функтор доступа, который делает это с указателем функции-члена в качестве члена.