Как мне создать объект функции, который изменяет свои аргументы? - PullRequest
0 голосов
/ 18 октября 2011

Я бы хотел заменить SomeFunction и SetArg на что-то более общее из boost.Похоже, что-то, что может быть сделано с bind в сочетании с lambda, но я не знаю, как.

Этот код очень прост, но я хотел бы заменить его, потому чтоМне нужен один для 2 и 3 и т.д. аргументов.

template<class T>
struct SomeFunction
{
    T value;
    SomeFunction(T s)
        : value(s) {}

    void operator()(T& s)
    {
        s = value;
    }
};

template<class T>
SomeFunction<T> SetArg(T value)
{
    return SomeFunction<T>(value);
}

Требования:

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

Следующий код демонстрирует использование:

void main()
{
    std::string t;
    SetArg(std::string("hello"))(t);
    assert(t == "hello");
}

Некоторый контекст:

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

struct Foo
{
    virtual void func1(std::string& s)
    {
    }
};

struct MockFoo : public Foo {
    MOCK_METHOD1(func1, void(std::string&));
};

void ExampleTestCase::example()
{
  MockFoo f;
  std::string s;

  EXPECT_CALL(f, func1(_))
      .WillOnce(Invoke(SetArg(std::string("hello"))));

  f.func1(s);

  CPPUNIT_ASSERT_EQUAL(std::string("hello"), s);
}

Invoke принимает функцию или функциональный объект.Внутри новой реализации func1 он вызывает объект функции, возвращаемый SetArg, и устанавливает в качестве аргумента строку "hello".

Invoke является частью gmock / gtest, а SetArg - нет.

1 Ответ

1 голос
/ 19 октября 2011

Вот что я придумал.operator() для setter, вероятно, потребует некоторой настройки, поскольку мы не извлекаем выгоду из возможной семантики перемещения здесь, но я не могу понять это прямо сейчас.

Также обратите внимание, что это интенсивно использует C++ 11 функций, которые могут быть вам недоступны.

#include <string>
#include <iostream>
#include <tuple>

// set arbitrary values to 
template<typename... Args>
struct setter {
  // needed because we cannot use initializer lists as they require assignment
  setter(const std::tuple<Args&...>& t) : t(t) {}
  std::tuple<Args...> t;

  // again a template to trigger deduction again
  template<typename... Args2>
  void operator()(Args2&&... args) {
    t = std::make_tuple(args...);
  }
};

template<typename... Args>
setter<Args&...> create_setter(Args&... args) {
  return setter<Args&...>(std::tie(args...));
}

int main()
{
  int i = 0;
  long l = 1;
  std::string foo = "foo";

  auto s = create_setter(i, l, foo);

  s(23, 42, "bar");
  std::cout << i << std::endl;
  std::cout << l << std::endl;
  std::cout << foo << std::endl;

  return 0;
}
...