Pascal  V
Pascal V

Reputation: 33

Could not deduce template argument when testing C++ with google mock

my code uses Google mock to test the class EventLogger.

In first place the compilation fails because the compiler does not find the parameter of the template in a macro, it fails deducting the argument :

candidate: template<class T, class ... Args> auto Filler<traceType>::fill(Args&& ...)
[with T = T; Args = {Args ...}; Class1 traceType = (Class1)1u]
 WRAP_MOCKED_TEMPL_METHOD_1(fill, T);
                            ^
In definition of macro 'WRAP_MOCKED_TEMPL_METHOD_1'
     auto NAME(Args &&...args)\
          ^
Template argument deduction/substitution failed:
     WRAP_MOCKED_TEMPL_METHOD_1(fill, T);

Couldn't deduce template parameter 'T''

So I tried to explicitly add the parameter when calling the function (comment //V2 in the code) but then appears an other error message: filler.fill<Message>(buffer, data, getMessage());

In member function
void EventLogger<traceType>::write(const buffer&, const Message&):
Error: expected primary-expression before '>' token
    `filler.fill<Message>(buffer, data, streamInd);`
                        ^

### Code ### Here is my code.

Class tested

template <Class1 traceType>
class EventLogger
{
public:
    template <typename Message>
    void write(const c1& buffer, const Message& data)
    {
        filler.fill(buffer, data, getMessage());            // V1
        filler.fill<Message>(buffer, data, getMessage());   // V2
    }

private:
    Filler<traceType> filler;
};

The MockClass

template <Class1 traceType>
class MockFiller
{
public:
    MOCK_METHOD3(send, void(c1, const Data::SendReq& msg, Class1::StreamInd&));
    MOCK_METHOD3(receive, void(c1, const Data::ReceiveReq& msg, Class1::StreamInd&));

    template <typename Message>
    void fill(c1 buffer, const Message&, Class1::StreamInd& streamInd)
    {
        ASSERT_TRUE(false);
    }
};

You can find the explanation of the macro MOCK_METHODX in Google documentation.

Specialization of the MockClass

template <>
template <>
void MockFiller<Class1::TYPE_1>::fill<Data::SendReq>(c1 buffer,
            const Data::SendReq& msg, Class1::StreamInd& streamInd)
{
    send(buffer, msg, streamInd);
}

template <>
template <>
void MockFiller<Class1::TYPE_1>::fill<Data::ReceiveReq>(c1 buffer,
            const Data::ReceiveReq& msg, Class1::StreamInd& streamInd)
{
    receive(buffer, msg, streamInd);
}

Constructor of the MockFiller

class MockFillerConstructor
{
public:
    MOCK_METHOD0(construct, std::shared_ptr<MockFiller<Class1::TYPE_1>>());
};

Class called in the class tested with its macro

#define WRAP_MOCKED_TEMPL_METHOD_1(NAME, TEMPL) \
template <typename TEMPL, typename ...Args>\
auto NAME(Args &&...args)\
{\
    return this->mock().NAME<TEMPL>(std::forward<Args>(args)...);\
}

template <Class1 traceType>
class Filler : public CopyableMockBase<MockFiller<traceType>>
{
public:
    WRAP_MOCKED_TEMPL_METHOD_1(fill, T);
};

So my questions are:

Thanks for your help

Upvotes: 3

Views: 776

Answers (1)

oisyn
oisyn

Reputation: 1376

I don't know anything about Google Mock, but your V2 is missing a template keyword:

filler.template fill<Message>(buffer, data, getMessage());   // V2

When EventLogger is parsed by the compiler, it does not know what Filler<traceType>::fill is supposed to be, and whether the < that follows is meant to open a list of template arguments or is simply a less-than operator. Without the template keyword, it assumes the latter.

Edit Oh wait a minute. For V1, of course it can't deduce T. Substituting the macro, you define Filler<traceType>::fill like this:

template <typename T, typename... Args>
auto fill(Args &&...args)
{
    return this->mock().fill<T>(std::forward<Args>(args)...);
}

(Also note the missing template in this->mock().fill<T> again here, but that's besides the point really). T is not referenced in the function parameter list. How is the compiler going to deduce what it's supposed to be? Why do you even need that T? Can't you just do the following?

template <typename... Args>
auto fill(Args &&...args)
{
    return this->mock().fill(std::forward<Args>(args)...);
}

Upvotes: 1

Related Questions