3

I learned a bit about variadic templates and searched over the Internet for some samples and now trying to write some tricky code to call member a method of a variadic class template with one of its fields. I can't understand why it doesn't work. Please, help.

Here is sample classes:

class BarBase
{
public:
    BarBase() = default;

    virtual void call() = 0;
};

template<typename O, typename M, typename... A>
class Bar
    : public BarBase
{
public:
    Bar(O* o, M m, A&&... a)
        : BarBase()
        , m_o(o), m_m(m), m_a(std::forward<A>(a)...)
    { }

    void call() override final
    {
        callInnerWithArgsInside();
    }

private:
    void callInnerWithArgsInside()
    {
        (m_o->*m_m)(m_a); // Some errors happends here
    }

    O* m_o;
    M m_m;
    std::tuple<typename std::remove_reference<A>::type...> m_a;
};

template<typename O, typename M, typename... A>
BarBase* crateBar(O* o, M m, A&&... a)
{
    return new Bar<O, M, A...>(o, m, std::forward<A>(a)...);
}

And call from main:

struct Foo
{
    void foo(int ii, float ff, std::string ss)
    {
        std::cout << "called" << std::endl;
    }
};

int main()
{
    Foo f;
    int i = 10;
    float ff = 20.2f;
    std::string s = "Hello";

    BarBase* bar = crateBar(&f, &Foo::foo, i, ff, s);
    bar->call();
}

Errors:

main.cpp

1>d:\drafts_tests\main.cpp(203): error C2198: 'void (__thiscall Foo::* )(int,float,std::string)' : too few arguments for call

1> d:\drafts_tests\main.cpp(202) : while compiling class template member function 'void Bar::callInnerWithArgsInside(void)'

1> with

1> [

1> O=Foo

1> , M=void (__thiscall Foo::* )(int,float,std::string)

1> ]

1> d:\drafts_tests\main.cpp(197) : see reference to function template instantiation 'void Bar::callInnerWithArgsInside(void)' being compiled

1> with

1> [

1> O=Foo

1> , M=void (__thiscall Foo::* )(int,float,std::string)

1> ]

1> d:\drafts_tests\main.cpp(214) : see reference to class template instantiation 'Bar' being compiled

1> with

1> [

1> O=Foo

1> , M=void (__thiscall Foo::* )(int,float,std::string)

1> ]

1> d:\drafts_tests\main.cpp(225) : see reference to function template instantiation 'BarBase *crateBar(O *,M,int &,float &,std::string &)' being compiled

1> with

1> [

1> O=Foo

1> , M=void (__thiscall Foo::* )(int,float,std::string)

1> ]

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

2
  • How exactly doesn't it work? Commented Jan 14, 2017 at 11:47
  • 1
    I think you're going to find this question a fascinating read. Commented Jan 14, 2017 at 11:48

1 Answer 1

2

you are passing a tuple to the function, rather than the individual type arguments. The following will pass the required type args to the call:

template<std::size_t... I>
void callInnerWithArgsInside2(std::index_sequence<I...>)
{
    (m_o->*m_m)(std::get<I>(m_a)...); 
}

void callInnerWithArgsInside()
{
    return callInnerWithArgsInside2( std::make_index_sequence<sizeof...(A)>());
}

live demo


EDIT1: C++11 version

I have implemented a C++11 version, see updated live demo

Sign up to request clarification or add additional context in comments.

2 Comments

Is it C++11 stuff "std::index_sequence", "std::make_index_sequence"?
apologies, you are correct, that was C++14, but I have implemented index_seq for C++11 in the past, see here for updated demo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.