Why can't I use std::unique_ptr as a “template<class> class” argument?

  • A+

This code:

#include <memory>  template <template <typename> class Ptr> class A { Ptr<int> ints; };  using B = A<std::unique_ptr>; 

yields the following error (with GCC 6.3):

a.cpp:6:28: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class Ptr> class A’  using B = A<std::unique_ptr>;                             ^ a.cpp:6:28: note:   expected a template of type ‘template<class> class Ptr’, got ‘template<class _Tp, class _Dp> class std::unique_ptr’ 

Now, I can work around this, like so:

template <typename T> using plugged_unique_ptr = std::unique_ptr<T>; using B = A<plugged_unique_ptr>; 

but why do I have to? I mean, why isn't the compiler willing to "plug" the second template parameter of std::unique_ptr with its default value and allow std::unique_ptr to be used as a template argument to A?


Because template template parameters need to match exactly. This means the default template argument is not relevant here. Note that extending your template template argument to two template arguments will only work by chance: an implementation is permitted to add more template arguments than defined by the standard, and some often do in the case of SFINAE around std containers.

This is also the prime reason I generally advise against using any template template arguments, and instead just use a plain template typename. If you need access to nested template types, provide internal accessors in line of e.g. value_type or external accessors such as tuple_element to access these inside the template.

Note: This apparently has changed in C++17, where the matching is not exact anymore, but slightly relaxed yet more complicated. Nevertheless, I would still advise against using template template parameters in general.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: