1

I can't find the right syntax even after reading cppreference on template params. The following doesn't compile, but hopefully describes what I want to do. What's the correct syntax?

template <class DisplayType>
class DisplayAdapter : public DisplayType
{

};

template<template <typename> DisplayAdapter>
class Painter // Takes an instance of DisplayAdapter, not a type!
{
}

Here is how it's supposed to be used:

struct S{};

int main()
{
    DisplayAdapter<S> concreteAdapter;
    Painter<concreteAdapter> p;

    return 0;
}

Here's Ideone snippet for the whole thing: https://ideone.com/dvbYt8

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • 2
    What's your compilation error and what's your code using both classes? Can you edit your question to include that? – Guillaume Racicot Jan 10 '18 at 23:50
  • what are you trying to achieve because DisplayAdapter is a class you can use it like Dispalyadapter and template taking a template doesnt make much sense – JoshKisb Jan 10 '18 at 23:56
  • It's not clear whether you want to use it like `Painter` or `Painter>`. – O'Neil Jan 11 '18 at 00:05
  • Could you explain more in depth what you're trying to do? – Guillaume Racicot Jan 11 '18 at 00:46
  • @O'Neil: neither, because, as the question stresses, `DisplayAdapter` is an object, not a type. An already-constructed object. – Violet Giraffe Jan 11 '18 at 06:13
  • @GuillaumeRacicot: GCC compiler. I've included the snippet. I don't think discussing the specific error is meaningful at this point, as the syntax is incorrect and I can't find the correct one. You can see for yourself via the Ideone link I've included in the question. – Violet Giraffe Jan 11 '18 at 06:16
  • @JoshKisb: hopefully, my addition to the question shows what I'm trying ot achieve. – Violet Giraffe Jan 11 '18 at 06:17

3 Answers3

3

What you're wanting is not a template template parameter.

A template template parameter is used to pass templates around, like this:

template<template<typename> typename Container>
struct foo {
    Container<int> container;
};

int main() {
    foo<std::vector> f;
}

As you can see, you can pass template names around with that. Remember that templates are not types, but a blueprint for type, and the language (and the standard) is not treating templates the same way as types.


I assume with your examples your trying to use non-type template parameters?

A non-type template parameter is a template parameter that is a value instead of a type. It can be of any integral types, reference type and pointer type.

For example, look at std::array:

std::array<int, 10> tenInts;

Notice the second parameter is a number. This is because std::array look something like this:

template<typename T, std::size_t N>
struct array { /* ... */ };

The second parameter is an unsigned long int.

You can also pass references and pointers as template parameter:

template<int& i> struct foo {};
template<int* i> struct bar {};

int main() {
    // Need at least internal linkage in C++14 and older
    // No linkage required since C++17, only static needed.
    static int num = 0;

    foo<num> f;
    bar<&num> b;
}

You can even pass a pointer to any type as reference template parameter:

struct stuff {};
template<stuff& s> struct foo;

int main() {
    static stuff s{};
    foo<s> f; // works!
}

This seem to be closer to what you wanted. However, you seem to have many many different type you want to send as template parameter, as the type of the instances you want to pass around are templated. For that you'll need C++17 template auto feature:

template<auto& da>
struct Painter {
    // ...
};

int main() {
    static DisplayAdapter<S> concreteAdapter;
    Painter<concreteAdapter> p;
}

And done!

If you don't have C++17 with you don't worry, and simply pass the display type along with your instance (C++14 example):

template<typename DT, DisplayAdapter<DT>& da>
struct Painter {};

// Internal linkage
DisplayAdapter<S> da;

int main() {
    Painter<S, da> painter;
}
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • Thank you! I have tried your last suggestion before posting this, but I didn't realize it must be a reference, so it didn't work. – Violet Giraffe Jan 11 '18 at 07:02
  • Still, specifying the `DT` type seems to be superfluous. Say I don't have C++ 17. Isn't there any way to at least infer `DT` automatically and only pass the object (`da`) when instantiating the template? – Violet Giraffe Jan 11 '18 at 07:04
  • @VioletGiraffe yeah, C++ still prohibits passing value of arbitrary types as template parameter, so they must be references or pointer. – Guillaume Racicot Jan 11 '18 at 07:04
  • @VioletGiraffe not in C++14 sadly. If you want, you can still duplicate the name of your instance with decltype to infer the tyle: `template` and use `Painter` but it's still not perfect I know. – Guillaume Racicot Jan 11 '18 at 07:07
1

If it was some simple type like int you would just use type instead of typename keyword e.g

template <int x>

or

template <std::vector<int>::value_type x>

But you can't put object of arbitrary type here.

More about non-type template parameters can be found in another Q&A

RiaD
  • 46,822
  • 11
  • 79
  • 123
  • Okay, thanks, I didn't realize. It can't take a non-`constexpr` object. But it can take a reference to such object, according to the top answer from your link? I can't seem to invent the right syntax for that, either. – Violet Giraffe Jan 11 '18 at 06:56
  • `template class` syntax is completely separate and needed to pass things like `std::vector` (without template parameters, so that they are added later). You need `template& adapter>` with fixed `X` or `template& adapter>` (and give X explicitely) or you may try `auto&` in c++17 but I've never used it (and not sure if it should work) – RiaD Jan 11 '18 at 07:37
0

You need to add class before DisplayAdater

template <class DisplayType>
class DisplayAdapter : public DisplayType
{

};

template<template <typename> class DisplayAdapter>
class Painter // Takes an instance of DisplayAdapter, not a type!
{
};

https://godbolt.org/g/mV7YRC

balki
  • 26,394
  • 30
  • 105
  • 151