У меня есть класс, который принимает входные данные, и иногда я хотел бы установить этот вход, назначая переменную, а в других случаях я хотел бы, чтобы класс вызывал функцию, чтобы получить свой ввод.
В прошлом я бы просто использовал std::function<T()>
в качестве входных данных, и установите лямбда-выражение для возврата значения некоторой внешней переменной, но я пытаюсь отучить от чрезмерного использования std::function
, Итак, я придумал std::variant<T, std::function<T()>>
:
template <typename T>
using functionable = std::variant<T, std::function<T()>>;
// return the T or the result of the T() from the variant
template <typename T>
T get(const functionable<T>& f) {
if (f.index() == 0)
return std::get<0>(f);
else
return std::get<1>(f)();
}
Реализовано таким образом:
class SomeClass {
private:
functionable<int> input_{0};
public:
SomeClass(const functionable<int>& input) : input_{input} {}
SomeClass& operator=(const functionable<int>& rhs) {
input_ = rhs;
return *this;
}
void print() { std::cout << get(input_) << '\n'; }
И использовал гибко таким образом:
SomeClass foo {42}; // init with assigned value
foo.print();
foo = 101; // overwrite assigned value
foo.print();
bool a{true};
// replace input value with input lambda
foo { [this]{if(a) return 10; else return 20;} };
foo.print();
a = !a; // useful if input predicates change
foo.print();
foo = 101; // replace std::function input with assigned int
foo.print();
Это улучшение по сравнению только с использованием std::function<T()>
для ввода и использования foo = []{return 42;}
для фиксированных входных значений?
Альтернативой может быть создание отдельных подклассов для назначенных и названных входов, но это приведет к комбинаторному взрыву, когда имеется более одного входа. Есть ли другие альтернативы, которые я пропускаю?
Математически говоря, постоянная функция — это просто другая функция. И в этом примере C ++, кажется, нет мотивирующей причины рассматривать константу как особый случай. Производительность, вероятно, будет примерно одинаковой, если большая часть ваших входных данных не является константой.
Кроме того, это functionable
не может быть использован с std::generate
в то время как std::function<>
обертывание постоянной банки. Это можно исправить, конечно, оборачивая functionable
в своем классе или захватывая одну в другую лямбду. Но это просто добавляет сложности, когда простое решение подойдет.
Других решений пока нет …