Aitch
Aitch

Reputation: 1697

C++ lambda testing interceptor/mock

I'm looking for a solution how I can create an interceptor/mock lambda to be able to check, whether it was called. What I tested was:

// test.hpp
template<typename R, typename ...Args>
std::function<R(Args&&...)> make_test_lambda(
    bool &called,
    std::function<R(Args&&...)> fn
) {
  called = false;

  return [&called, f=std::move(fn)](Args&&... args) {
    called = true;
    return f(std::forward<Args>(args)...);
  };
}

// test.cpp: test with "catch"
bool called;
function_under_test(make_test_lambda(called, [](int x) {
    REQUIRE(x == 4);
}));

REQUIRE(called);

It doesn't work no matching function for call. Can you help me?

Thank you very much!

Upvotes: 1

Views: 784

Answers (1)

llllllllll
llllllllll

Reputation: 16424

The problem is that every lambda has a unique type only known to the compiler. The template argument deduction takes place when compiler is selecting candidate functions, before determining the set of viable functions. Roughly speaking, a template function will be included in the candidate set, only if all the types can match exactly. Conversion is not allowed.

In your case, replacing your std::function<> with a more generic template parameter Func is just ok. Like the following code:

template<class Func>
struct wrapper
{
    wrapper(Func f, bool &called)
        : f_(f)
        , called_(called)
    {}

    template<class... Args>
    decltype(auto)
    operator() (Args&& ...args)
    {
        called_ = true;
        return f_(std::forward<Args>(args)...);
    }
private:
    Func f_;
    bool &called_;
};

template<class Func>
auto 
make_test_lambda(bool &called, Func func)
{
    called = false;
    return wrapper<Func>(func, called);
}

Upvotes: 3

Related Questions