Например, у меня есть вызов функции в некотором коде, который я хочу включить / отключить, как мне нравится.
Обычно я мог бы просто использовать if, но тогда он каждый раз проверял бы, можно ли запустить функцию, чего я не хочу. Я просто хочу, чтобы код никогда не делал эту проверку.
Блоки ifdef могут быть грязными и довольно грязными, они накапливаются и затрудняют чтение кода.
Разве я не могу решить это с помощью какого-то шаблона? Я знаю, что могу сделать несколько лямбд для создания каждой версии возможного вызова функции, который я хотел бы.
Это то, что означает статический, если? Потому что, на мой взгляд, я хочу сделать самоизменяющийся код, который я не знаю, хорошая ли это идея или вообще возможна.
Если я не понял ваш вопрос, я думаю, вы хотите что-то вроде Шаблон дизайна стратегии что для принятия решения во время выполнения.
Но только потому, что вы попросили шаблон, вот пример использования Основанное на политике метапрограммирование шаблона …
Но здесь решение принимается во время компиляции.
struct task {
void do_task() { /* really do the task... */ }
};
struct no_task {
void do_task() {} // empty
};
template<typename Task> class host : public Task {};
// here you take the decision...
// you can pass either task or no_task
host<task> h;
// and later you call the function...
h.do_task();
Использование шаблонов действительно эффективно.
Нет никакого косвенного обращения через любой указатель на функцию.
Компиляторам легко встроить функцию.
Если вы передадите это no_task
сайт вызова даже не будет вызывать пустую функцию (проверьте это с уровнями оптимизации вашего компилятора).
Хотя существует множество сложных решений этой проблемы, указатель на функцию — это простой метод (хотя я сомневаюсь, что его производительность значительно лучше, чем только условная).
#include <functional>
#include <iostream>
void option1(int) {
std::cout << "option 1\n";
}
void option2(int) {
std::cout << "option 2\n";
}
std::function<void(int)> fp(option1);
int main() {
fp(3);
// Let's change what fp does:
fp = option2;
fp(3);
}
Вы можете использовать функцию перегрузки и логический параметр шаблона:
template<bool B>
class X{
// Function to be called when B is true
void foo(std::true_type) {
..
}
// Function to be called when B is false
void foo(std::false_type) {
... // leave empty to do nothing if B is false
}void bar(){
// This will call either of the foos depending on B
foo(std::integral_constant<bool,B>());
}
}
Пояснение: Типовая черта std::integral_constant
будет либо оценить значение типа std::true_type
или же std::false_type
в зависимости от того B
это правда или ложь. Этот тип будет использоваться в разрешении перегрузки, поэтому компилятор выберет правильный метод для вас. Вы можете просто определить одну из функций как пустую. Это похоже на «отключение» вызова, когда B
ложно, например.
Решение о том, какую функцию вызывать, делается во время компиляции, поэтому вы страдаете нет время выполнения для этого решения.
Да, есть способы сделать то, что вы хотите, но, поскольку они выполняются во время выполнения, они определяют стоимость. Относительно того, что я даю ниже, быстрее или медленнее, чем если … Вам придется профилировать и посмотреть. Вы платите за разыменование, но теряете лишнюю ветку.
Функциональные указатели
Вы можете решить эту проблему, имея несколько версий функций (или объектов с виртуальными функциями).
Пример:
void stud(const char *) {}
void _log(const char *msg) { clog << msg << endl; };
void (*log)(const char *) = stud;
void enable_logging() { log = _log; }
void disable_logging() { log = stud; }
int main() {
log("This will not be logged");
enable_logging();
log("This will be logged.");
}