Есть, с небольшим количеством sfinae.
template<class, typename Fallback, typename = void>
struct type_or_default {
using type = Fallback;
};
template<class C, typename F>
struct type_or_default<C, F, std::void_t<typename C::type>> {
using type = typename C::type;
};
При этом используется стандартное соглашение, в котором мета-функции шаблона предоставляют имя члена type
, но вы можете адаптировать его для своих собственных нужд именования.Единственный не-C ++ 14 бит здесь - std::void_t
, но эквивалентная вещь может быть реализована в C ++ 14 (его просто нельзя поместить в пространство имен std
).Вы используете его в своем классе следующим образом:
template <typename T = foo>
struct bar
{
using type = typename type_or_default<T, double>::type;
};
Здесь происходит то, что компилятор выполняет сопоставление с образцом при выборе специализации шаблона.Если у класса C
есть член type
, то предоставленная нами частичная специализация будет считаться более специализированной и как таковая выбранной.В противном случае (если замена не удалась при проверке специализации), первичный шаблон всегда будет там, к которому можно обратиться.
Живая программа , с которой нужно повозиться.