Inheriting off of a list of templated classes, when supplied with the list of template arguments

倾然丶 夕夏残阳落幕 提交于 2020-01-24 05:53:04

问题


I'm trying to write some metaprogramming code such that:

  • Inheriting from some class foo<c1, c2, c3, ...> results in inheritance from key<c1>, key<c2>, key<c3>, ...
  • The simplest approach doesn't quite work because you can't inherit from the same empty class more than once.
  • Handling the "..." portion isn't pretty (since it's copy-pasta), but works.

Okay, so, here's the attempt:

template<char c0, typename THEN, typename ELSE>
struct char_if
{
    typename THEN type;
};
template<typename THEN, typename ELSE>
struct char_if<0, THEN, ELSE>
{
    typename ELSE type;
};
class emptyClass {};


template<char c> class key
{
    char getKey(){return c;}
};

template<char c0, char c1, char c2, char c3, char c4>
class inheritFromAll
{
    typename char_if<c0, key<c0>, emptyClass>::type valid;

    class inherit
        : valid
        , inheritFromAll<c1, c2, c3, c4, 0>::inherit
    {};
};

template<char c1, char c2, char c3, char c4>
class inheritFromAll<0, c1, c2, c3, c4>
{
    class inherit {};
};

template<char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0, char c4 = 0>
class whatINeedToDo
    : public inheritFromAll<c0, c1, c2, c3, c4>::inherit
{
    bool success(){return true;}

};

int main() 
{
    whatINeedToDo<'A', 'B', 'c', 'D'> experiment;
    return 0;
}

I had originally though I could use Boost::Mpl to do it, but I honestly couldn't figure out how; I couldn't figure how you'd pass around a list<...> without always explicitly knowing the ... part.

Just doing:

template<> class key<0> {};

doesn't work because if I then have more than one 0 parameter, I try to inherit from the same thing twice. (If you can think of workaround for that, that'd also work).

I also haven't tried macros, because I think I know them less than I know metaprogramming, so they might work as a solution.

Any ideas?

Edit: I have a bad solution. I'd still like a meta-programming solution, for the learning, but the bad solution is this:

template<char c1, char c2, char c3> class inheritFromMany
    : public key<c1>
    , public key<c2>
    , public key<c3>
{

};
template<char c1, char c2> class inheritFromMany<c1, c2, 0>
    : key<c1>
    , key<c2>
    {

    };

Edit2: Woof, but I forgot a part. I need to pass a variable to the constructor of ''key'' - it's the same in all cases, but it's necessary.

Edit3: Addressing comments:

  • I'm not expecting the user to submit the same character more than once. If they did, I would only only want to inherit from that key once - I mean, I guess I didn't mention that because you can't do that? Which is why other, simpler solutions don't work?
  • The actual point of this is that key is a wrapper for a signal/slot (channel) behavior. The channel keeps a list of callbacks, which is actually just virtual key<ch>::callback. So, inheriting from a key gives you access to that key's channel, lets (or makes) you supply a callback. keyInput<ch1, ch2, ch3,...> is then a wrapper for that, so you don't have to key<ch1>, key<ch2>, key<ch3>

回答1:


Without you saying what you actually want to achieve, this is a mostly academic exercise... but here is one way how you'd use MPL to inherit linearly:

template<class T> struct key {
    enum { value = T::value };
    char getKey() { return value; }
};

template<class Values> struct derivator 
    : mpl::inherit_linearly<
          Values
        , mpl::inherit< mpl::_1, key<mpl::_2> >
        >::type
{};

// usage:    
typedef mpl::vector_c<char, 1,2,3> values;
typedef derivator<values> generated;

// or:
derivator< mpl::vector_c<char, 1,2,3> > derived;

Maybe you can clarify on that basis what you need.

I need to pass a variable to the constructor of ''key'' - it's the same in all cases, but it's necessary.

Do you mean you want to pass a parameter through the inheritance-chain to all constructors? Then take a look at the solutions to this question.


As for avoiding mpl::vector_c in the visible interface, you could use your previous approach and build it internally by only inserting values not equal to zero in it:

template<char c, class S> struct push_char {
    typedef typename mpl::push_front<S, mpl::char_<c> >::type type;
};

template<class S> struct push_char<0, S> {
    typedef S type; // don't insert if char is 0
};

template<char c1=0, char c2=0, char c3=0>
struct char_vector { 
    // build the vector_c
    typedef 
        typename push_char<c1
      , typename push_char<c2
      , typename push_char<c3
      , mpl::vector_c<char> 
      >::type>::type>::type
    type; 
};

template<char c1=0, char c2=0, char c3=0> 
struct derivator 
    : mpl::inherit_linearly<
          typename char_vector<c1,c2,c3>::type
        , mpl::inherit< mpl::_1, key<mpl::_2> >
        >::type
{};


来源:https://stackoverflow.com/questions/2338049/inheriting-off-of-a-list-of-templated-classes-when-supplied-with-the-list-of-te

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!