简体   繁体   中英

Template template non-type parameter

I am not really sure if there's such a feature in C++, and if there is I can't seem to make it work, so I decided to ask. Can I have a template template non-type parameter. Something like this:

template<template<int> class A, int num>
class C
{
private:
     A<num> obj;
};

My main issue is that I want to have a class C that accepts 2 classes as template parameters. Both of these classes specialize over a non-type parameter - say A<5>, B<5> and I want to pass them to class C which accepts two classes as template parameters. I need to make sure however that both of these classes specialize over the same non-type parameter - for example A<3>, B<4> shouldn't be allowed as arguments to class C.

My bad, after some tinkering I managed to call it right. The issue was I was calling C<A<5>> and i needed to obviously call C<A, 5> . Here's an example of how I made the whole thing work just in case if anybody ever needs it:

template<int a, int b, int c>
class Anac
{
public:
    void print()
    {
        std::cout << "Anac: " << a << " " << b << " " << c << "\n";
    }
};
template<int a, int b, int c>

class Mamut
{
public:
    void print()
    {
        std::cout << "Mamut: " << a << " " << b << " " << c << "\n";
    }
};

template <class C>
class R
{

};

template< template<int, int, int> class A, template<int, int, int> class B, int a, int b, int c>
class gm
{
private:
    A<a,b,c> p1;
    B<a,b,c> p2;
public:
    void print()
    {
        p1.print();
        p2.print();
    }
};
int main()
{
    gm<Anac, Mamut, 3, 4, 5> game;
    game.print();
    std::cin.ignore();
    return 0;
}

You may want to simplify your code with a "makeC":

#include <iostream>

template <template<int> class A, template<int> class B, int N>
class C {
    A<N> a;
    B<N> b;
};

using namespace std;

template <template<int> class A, template<int> class B, int N>
C<A,B,N> makeC(A<N> a, B<N> b) {
    return C<A, B, N>{};
}

template<int N>
class AImpl {

};

template<int N>
class BImpl {

};


int main() {
    auto c = makeC(AImpl<2>{}, BImpl<2>{});
    //auto error = makeC(AImpl<1>{}, BImpl<2>{});

    return 0;
}

A similar approach would be to do something like this:

template<int I>
class A {};

template<int I>
class B {};

// Forward declaration.
template<typename T, typename U>
class C;

template<template<int> class TA, template<int> class TB, int I, int J>
class C<TA<I>, TB<J>> {
    // J exists only to make sure integer parameters match.
    static_assert((I == J), "Template parameters' integer parameters are mismatched.");

  private:
    TA<I> objA;
    TB<I> objB;

  public:
    // ...
};

// ...

C<A<4>, B<4>> ca4b4;   // Valid.
C<A<4>, B<16>> ca4b16; // Static assert fails.

This will allow you to guarantee that both containers have the same integer parameter, and emit a readable error message if they don't.



Edit: Note that if you don't use two separate integer parameters and manually check for equality, attempting to create an instance with mismatching template template parameters will give off a less understandable "incomplete type" error message.

template<template<int> class TA, template<int> class TB, int I>
class C<TA<I>, TB<I>> {
    // ...
};

// ...

C<A<4>, B<16>> ca4b16; // Oops.
/* Error messages:
 * GCC:
 *   error: aggregate 'C<A<4>, B<16> > ca4b16' has incomplete type and cannot be defined
 *      C<A<4>, B<16>> ca4b16;
 *                     ^
 * MSVC:
 *   error C2079: 'ca4b16' uses undefined class 'C<T, U>'
 *      with
 *      [
 *          T=A<4>,
 *          U=B<16>
 *      ]
 */

This is because the actual definition will only be able to catch instances where both parameters have the same integer parameter, and any usage with mismatching integer parameters will instead fall back on the forward declaration, which is incomplete. Using two separate integer parameters, then manually checking for equality, allows us to catch bad instantiations instead of letting them fall back on the declaration, so we can convert that generic error into something that actually tells you what the problem is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM