Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use variadic template in C++ while keeping my implementor class private?

#include <cstdio>

class builtin_pack
{
    long v[4];
public:
    builtin_pack ( long v1, long v2, long v3, long v4 ) : v{v1, v2, v3, v4} {}
    void builtin_op()
    {
        printf ( "%lx,%lx,%lx,%lx\n", v[0], v[1], v[2], v[3] );
    };
    template<typename Func, typename... Targs>
    void builtin_apply ( Func f, Targs ... t )
    {
        for ( int i = 0; i < 4; i++ )
        {
            v[i] = f ( t.v[i]... );
        }
    }
};

class pack : builtin_pack
{
public:
    pack ( long v1, long v2, long v3, long v4 ) : builtin_pack ( v1, v2, v3, v4 ) {}
    template<typename Func, typename... Targs>
    pack& apply ( Func f, Targs ... t )
    {
        this->builtin_apply ( f, t... );
        return *this;
    }
    void op()
    {
        this->builtin_op();
    }
};

int main()
{
    pack p1{0xff, 0x0f, 0xf0, 0x06}, p2{0x0f00, 0xf000, 0x6700, 0xff00};
    pack p3{0x12340000, 0x56780000, 0x45120000, 0xdead0000};
    p3.apply ( [] ( long i, long j, long k )->long{return i | j | k;}, p1, p2, p3 );
    p3.op();
    return 0;
}

That code compiles with an error:

main.cpp:17:24: error: cannot cast 'pack' to its private base class 'builtin_pack'
            v[i] = f ( t.v[i]... );
                       ^
main.cpp:29:15: note: in instantiation of function template specialization 'builtin_pack::builtin_apply<(lambda
      at main.cpp:42:16), pack, pack, pack>' requested here
        this->builtin_apply ( f, t... );
              ^
main.cpp:42:8: note: in instantiation of function template specialization 'pack::apply<(lambda at
      main.cpp:42:16), pack, pack, pack>' requested here
    p3.apply ( [] ( long i, long j, long k )->long{return i | j | k;}, p1, p2, p3 );
       ^
main.cpp:22:14: note: implicitly declared private here
class pack : builtin_pack
             ^~~~~~~~~~~~
main.cpp:17:26: error: 'v' is a private member of 'builtin_pack'
            v[i] = f ( t.v[i]... );
                         ^
main.cpp:22:14: note: constrained by implicitly private inheritance here
class pack : builtin_pack
             ^~~~~~~~~~~~
main.cpp:5:10: note: member is declared here
    long v[4];
         ^
2 errors generated.

What I want to do is to implement a mapping method with a custom (lambda) function (called 'apply'). It works readily when the hierarchy of private implementor-public wrapper is absent, so when the array v is just in the class pack, it compiles and runs as expected. However, it does not work when data is stored in a private-inherited class.

The structure of the class is a private implementor class along with a wrapper class, and in the middle I encountered this error.

Have I used the variadic template the wrong way? Or is there a workaround available?

(Sorry for my poor expression as I am a newbie in C++ and stackoverflow and non-native speaker of English, and modification or suggestion of the question is welcomed as long as the original intention is reserved!)

like image 660
Thiner Avatar asked Oct 20 '16 11:10

Thiner


People also ask

What are variadic function templates in C++?

Variadic function templates in C++. Variadic templates are template that take a variable number of arguments. Variadic function templates are functions which can take multiple number of arguments.

What are the contents of the variadic template arguments?

The contents of the variadic template arguments are called parameter packs. These packs will then be unpacked inside the function parameters. For example, if you create a function call to the previous variadic function template... Syntax - the sizeof... operator (sizeof...):

Do I need to know C++ to use D's Variadic templates?

Although the D programming language also provides the use of variadic templates, only variadic templates offered by C++11 standard will be covered here, so knowledge of D programming language's variadic templates is not required in order to read & understand this article.

What are variadic arguments in C++?

Douglas Gregor and Jaakko Järvi came up with this feature for C++. Variadic arguments are very similar to arrays in C++. We can easily iterate through the arguments, find the size (length) of the template, can access the values by an index, and can slice the templates too.


1 Answers

Your problem is that with private inheritance, you cannot convert from pack* to builtin_pack* (outside of pack, that is). If you do cast it, the code compiles, although I'm not sure if this is what you were after:

template<typename Func, typename... Targs>
pack& apply ( Func f, Targs ... t )
{
    this->builtin_apply ( f, static_cast<builtin_pack&&>(t)... );
    return *this;
}

live demo

like image 96
krzaq Avatar answered Sep 29 '22 08:09

krzaq