Hooked
Hooked

Reputation: 88168

Correct practice using 'using' in C++ templates

I have a small class that uses several STL lists internally

template<class T>
class MC_base {

  using OBJ_LIST  = std::list<T>;
  using OBJ_VAL   = typename OBJ_LIST::value_type;
  using OBJ_ITR   = typename OBJ_LIST::iterator;
  using OBJ_CITR  = typename OBJ_LIST::const_iterator;

  OBJ_LIST A,B,C;
  ...
};

With the using statements, if I write an iterator inside the class definition, it looks nice and clean:

OBJ_ITR begin() { return A.begin(); };
OBJ_ITR end()   { return A.end();   };
OBJ_CITR begin() const { return A.begin(); };
OBJ_CITR end()   const { return A.end();   };

Writing new functions, again inside the class definition, is easy since I can simply use the names OBJ_XXXX names when needed. Furthermore, if I decide to change the container type (to say std::vector) at some point later, I only have to change one line and as long as my new container supports all the same actions everything should be seamless.

This is problematic however when I want to define a new class function outside of the class definition

template<class T>
OBJ_ITR MC_base<T>::foo(OBJ_ITR x) { ... }

I'm not sure how to "bring out" the using statements so they work correctly with the templates and not to define them for every function which would be overly verbose. Also, I don't want to pollute the namespace with my using statements.

Is there a proper way to use using with templates?

Upvotes: 4

Views: 300

Answers (2)

Mike Seymour
Mike Seymour

Reputation: 254501

You can use a trailing return type. The type is looked up in the scope of the class, as with the parameter types, so nested types don't need qualification.

template<class T>
auto MC_base<T>::foo(OBJ_ITR x) -> OBJ_ITR { ... }

Upvotes: 5

Ben Voigt
Ben Voigt

Reputation: 283684

Outside the class, you need to qualify the names. You additionally need to use the typename keyword to promise the compiler that those names are types in every specialization.

template<class T>
typename MC_base<T>::OBJ_ITR MC_base<T>::foo( typename MC_base<T>::OBJ_ITR x ) { ... }

9.3p2 requires that

A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition.

Which prevents using a more nested scope for the definition where these names would be present. Not to mention the problem that those names depend on the template parameter.


The best solution is probably to write those functions inline. These are members of a template class, so they have to be included in the header file anyway.

Upvotes: 5

Related Questions