lucmobz
lucmobz

Reputation: 483

Extract first template parameter from a template template parameter and using it inside the class?

I have the following problem: a class template A with several template parameters, I want to build a class B that takes A as template parameter and extract the first template parameter of A in order to use it in some method(think of extracting int from std::vector<int> and returning the default int{}).

#include <iostream>

template<typename... Ts>
struct A {};

template<template <typename InnerType> typename U> // <--- I'd like to use InnerType!
struct B {
  InnerType foo() { return InnerType{}; }
};

int main()
{
  B<A<int>> b;
  std::cout << b.foo() << "\n"; 

  return 0;
}

I knew this naive way wouldn't compile, but I can't figure out how to achieve something like that. Any tip is appreciated.

Upvotes: 2

Views: 566

Answers (2)

There is no InnerType. It's a mnemonic. A documentation of the expected purpose for the template's first parameter. And it's completely optional. The declaration of B is equivalent to

template<template <typename> typename U> // No name
struct B {
  InnerType foo() { return InnerType{}; } // What now?
};

Class templates aren't types. They are factories that produce types. You can't query a factory for the argument it will use, because it doesn't know it yet. Furthermore, you define B to accepts a template as a parameter, when in fact you intend to feed it a type. That's an argument/parameter mismatch right there.

But you can query the results of the factory. If you change the definition of B to accept types instead of templates, you can then specialize it on types that were created from a template. This will make both the factory and the arguments it used deducible.

Upvotes: 2

cigien
cigien

Reputation: 60208

You can't name the template parameter of a template template parameter directly. Even though it looks like you can name it, as you noticed that name can't actually be used.

However, you can use explicit specializations for a type that takes a single template parameter.

template<typename... Ts>
struct B;  // incomplete type, only needed for specialization

template<template <typename> typename U, typename InnerType>
struct B<U<InnerType>>  // specialized to be able to use InnerType
{  
  InnerType foo() { return InnerType{}; }
};

Here's a demo.

You could of course do something similar for templates with more than one parameter by adding specializations for those cases as well.

Upvotes: 4

Related Questions