Использование std :: variable <T, std :: function <T () >> в качестве гибкого ввода вместо подклассов - PullRequest
0 голосов
/ 03 сентября 2018

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

Раньше я бы просто использовал 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;} для фиксированных значений ввода?

Альтернативой может быть создание отдельных подклассов для назначенных и названных входов, но это привело бы к комбинаторному взрыву, когда имеется более одного входа. Есть ли другие альтернативы, которые мне не хватает?

1 Ответ

0 голосов
/ 03 сентября 2018

Математически говоря, постоянная функция - это просто другая функция. И в этом примере C ++, кажется, нет мотивирующей причины рассматривать константу как особый случай. Производительность, вероятно, будет примерно одинаковой, если большая часть ваших входных данных не является константой.

Кроме того, этот functionable нельзя использовать с std::generate, тогда как std::function<> может обернуть постоянную банку. Конечно, это можно исправить, обернув functionable в отдельный класс или захватив один в другой лямбда-класс. Но это просто добавляет сложности, когда простое решение подойдет.

...