#c #templates #c 14
#c #шаблоны #c 14
Вопрос:
Я хотел бы создать a, typedef
который зависит от существования typedef
в аргументе шаблона:
struct foo
{
using MyType = int;
};
template <typename T = foo>
struct bar
{
// Pseudo code
#if T::MyType is defined
using MyType = T::MyType;
#else
using MyType = double;
#endif
};
Есть ли способ заставить его работать, используя std::conditional
или что-то еще в C 14?
Комментарии:
1. Используйте SFINAE
Ответ №1:
Есть, с небольшим количеством 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
, то предоставленная нами частичная специализация будет считаться более специализированной и как таковая выбрана. В противном случае (если замена завершается неудачей при проверке специализации), всегда можно вернуться к основному шаблону.
Живая программа, с которой можно повозиться.
Комментарии:
1. Кстати, поздравляю со 100 кб
2. @SombreroChicken — Большое вам спасибо! Теперь мне просто нужно решить, стоило ли это такой цены, в основном моего здравомыслия
3. @SombreroChicken — Я углубился в C только потому, что кто-то однажды ошибся в SO. Затем просто свернулся с ним.
4. Хм, мог бы быть я
5. @StoryTeller запоздалый вопрос, зачем нам
typename = void
в качестве третьего аргумента шаблона в первой функции?
Ответ №2:
Мои пять центов на этот вопрос.
#include <type_traits>
template <typename T, typename DefaultType>
struct CalculateMyType {
template <typename C>
static typename C::MyType test(typename C::MyType*);
template <typename>
static DefaultType test(...);
typedef decltype(test<T>(nullptr)) MyType;
};
struct foo
{
using MyType = int;
};
template <typename T = foo>
struct bar
{
using MyType = typename CalculateMyType<T, double>::MyType;
};
struct baz
{
};
struct quux
{
using MyType = float;
};
#include <iostream>
#include <typeinfo>
template <typename>
struct TypeToStr;
template<> struct TypeToStr<double> { const char * name = "double"; };
template<> struct TypeToStr<float> { const char * name = "float"; };
template<> struct TypeToStr<int> { const char * name = "int"; };
int main() {
std::cout << "bar<foo>::MyType = " << TypeToStr<bar<foo>::MyType>().name << std::endl;
std::cout << "bar<baz>::MyType = " << TypeToStr<bar<baz>::MyType>().name << std::endl;
std::cout << "bar<quux>::MyType = " << TypeToStr<bar<quux>::MyType>().name << std::endl;
}