Home > database >  Inject default template argument type from user code
Inject default template argument type from user code

Time:02-11

Is there a way to "inject" a default type for a template member function of a template class "after" the definition of said template member function?

Basically similar to this (which does not compile), so that I can specify NS::Default (the default type for Z) outside of the library in which template class S and its member function template are defined:

// In library
namespace NS {}

template<typename T>
struct S {
  template<typename X, typename Z = NS::Default>
  void foo(X x, Z z = Z{}) {}
};


// In user code
namespace NS {
  using Default = int;
}

S<SomeClass> s;
s.foo(3.14); // z == int(0)

I think I once had code like this working with later specified type traits, but it's been a while and my template foo is a bit rusty.

Primary goal is to be able to call S::foo with just one argument and have it use a default argument with a default type, which is specified NOT by the library but rather the using code.

Injection of that type via the class templates is of course an option but NOT what I'm asking for. So I don't want to have to do:

// library
template<typename T, typename ZDefault>
struct S {
  template<typename X, typename Z = ZDefault>
  void foo(X x, Z z = Z{}) {}
};

// User
S<SomeClass, int> s;
s.foo(3.14);

CodePudding user response:

You can create a traits that customer should define/specialize:

// In library
template <typename> struct DefaultType; // declaration without definition.

template<typename T>
struct S {
  template<typename X, typename Z = typename DefaultType<X>::type>
  void foo(X x, Z z = Z{}) {}
};


// In user code
template <typename> struct DefaultType
{
    using type = int;
};

S<SomeClass> s;
s.foo(3.14); // z == int(0)

CodePudding user response:

If you can expect your clients to be in full control of their types, you could design the lib so that the default type is part of the parameterized T type of the class template S:

// In library
/// @attention `T` shall have a public alias declaration name `Default`
template<typename T>
struct S {
  template<typename X, typename Z = typename T::Default>
  void foo(X x, Z z = Z{}) {}
};

// In user code

// Default config for all my types: let my type inherit from this class.
struct DefaultConfig {
   using Default = int;
};

struct SomeClass : DefaultConfig {};

int main() {
    S<SomeClass> s;
    s.foo(3.14); // z == int(0)
};
  • Related