Шаблон нетипичного параметра с разными типами - PullRequest
2 голосов
/ 23 апреля 2019

Предположим, что входной параметр шаблона T может иметь или не иметь внутреннюю переменную bar.Я пытаюсь написать структуру, которая возвращает значение bar, когда оно у нас есть, и возвращает некоторую константу, когда ее нет.Вот моя попытка:

struct A {
  static constexpr unsgined int bar = 20;
  hasBar = true;
};

struct B {
  hasBar = false;
};

template <typename T, typename std::enable_if<T::hasBar, int>::type>
struct getBar {
  static constexpr unsigned int bar = T::bar;
};

template <typename T, typename std::enable_if<!T::hasBar, int>::type>
struct getBar {
  static constexpr unsigned int bar = 0;
};

int main() {
  getBar<A>::bar; // Expect 20
  getBar<B>::bar; //Expect 0
}

Я не могу скомпилировать этот код с C ++ 14.Компилятор жалуется, что: «шаблонный тип не относится к типу другого типа».

Почему у нас такая ошибка и как я могу ее исправить?

Ответы [ 3 ]

3 голосов
/ 23 апреля 2019

Вы можете определить, существует ли ::bar напрямую, без необходимости hasbar

что-то вроде ...

#include <type_traits>
#include <iostream>
struct A {
  static constexpr unsigned int bar = 20;

};

struct B {

};


template <typename T,typename=void>
struct getBar {
  static constexpr unsigned int bar = 0;
};

template <typename T>
struct getBar<T,std::void_t<decltype(T::bar)>> {
  static constexpr unsigned int bar =  T::bar;
};

int main() {
  std::cout << getBar<A>::bar << std::endl; // Expect 20
  std::cout << getBar<B>::bar << std::endl; //Expect 0
}

Демо

2 голосов
/ 23 апреля 2019

Другое решение, которое не нуждается в hasBar, а просто обнаруживает присутствие bar (а также поддерживает первоначальный тип bar, если отличается от int)

struct A
 { static constexpr unsigned int bar = 20; };

struct B
 { };

template <typename T>
constexpr auto getBarHelper (int) -> decltype( T::bar )
 { return T::bar; }

template <typename T>
constexpr int getBarHelper (long)
 { return 0; }

template <typename T>
struct getBar
 { static constexpr auto bar { getBarHelper<T>(0) }; };

int main()
 {
   static_assert( 20u == getBar<A>::bar, "!" );
   static_assert(  0  == getBar<B>::bar, "!" );
 }
2 голосов
/ 23 апреля 2019

Шаблоны классов не могут быть перегружены (как шаблоны функций); Вместо этого вы можете использовать специализацию . например,

template <typename T, typename = void>
struct getBar {
  static constexpr unsigned int bar = 0;
};

template <typename T>
struct getBar<T, std::enable_if_t<T::hasBar>> {
  static constexpr unsigned int bar = T::bar;
};

ЖИТЬ

...