I'd like to replace SomeFunction
and SetArg
with something more generic from boost
.
It looks like something that can be done with bind
in combination with lambda
, but I don't know how.
This code is very simple but the reason I'd like to replace it is because I need one for 2
and 3
etc arguments.
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);
}
The requirements:
ctor
, but any other way is also fine.The following code demonstrates the usage:
void main()
{
std::string t;
SetArg(std::string("hello"))(t);
assert(t == "hello");
}
Some context:
I want to test the client code of class Foo
. So I want to replace the implementation of func1
with my own, but in a flexible way.
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 takes a function or function object. Inside the new implementation of func1
it calls the function object returned by SetArg
and sets its argument to the string "hello"
.
Invoke is part of gmock/gtest but SetArg
is not.
Here is what I came up with. The operator()
of setter would probably
require some tweaking as we are not really benefiting from the
possible move semantics here, but I can't figure that out right now.
Also note that this makes heavy use of C++11 features which might not be available to you.
#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;
}