Home > database >  Using type defined inside templated type
Using type defined inside templated type

Time:01-03

Is there any nice way to do the following?

                                 /* vvv */
template<typename Wrapper> using T = typename Wrapper::type
T f(const T &a, const T &b) { 
    return a   b; 
}

where Wrapper is some class which contains (several) types defined inside of it.

I can do the following, but I don't like this approach as it makes the function have several templated types (and also does not have the exact same meaning):

template<typename Wrapper, typename T = typename Wrapper::type>
T f(..)

I want to do this purely to reduce boilerplate of typing typename Wrapper::type in the function declaration. If there is a better way to do this, please let me know.

Note: in my project the Wrapper type needs to satisfy some concept, which also requires having the type type defined inside the type Wrapper.


If it may help, here is my use case. I am (attempting) to write a linear algebra library. In this scenario, in order to create objects such as vectors or matrices, we need to supply a field F, which must satisfy:

  • F is over some elementary type T (available by e.g., F::type)
  • F is supplied with two operations OpAdd and OpMul, both of which can operate on T.

Defining this using concepts is simple, however this adds some clutter, such as my example above.

CodePudding user response:

Do you know what the type will be? If so you can supply the template argument:

template<class T>
using inner = typename T::type;

template<class T>
inner<T> f(inner<T> const& a, inner<T> const& b);

// ...
f<X>(y, y);

CodePudding user response:

In requested circumstances, what you don't like is the only solution

#include <type_traits>

template<typename Wrapper,
         typename T = typename Wrapper::type,
         typename std::enable_if<std::is_same<T, typename Wrapper::type>::value>::type* = nullptr>
T f(const T &a, const T &b) { 
    return a   b; 
}

struct S {
  typedef long type;
};

int main() {
  f<S>(0L, 0L);   // ok
  // f<S>(0, 0);  // failure

  // If the second type is set explicitly 
  f<S, long>(0L, 0L);    // ok
  f<S, long>(0, 0);      // ok
  // f<S, int>(0L, 0L);  // failure
  // f<S, int>(0, 0);    // failure
}

This is a better solution than one with inner<T>, because f<S>(0, 0) will not fail with inner<T> - the exact long is required but int is passed.

  • Related