Рассмотрим следующий пример
template<class Type = void> class MyClass
{
public:
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (/* SOMETHING */) ? (_x) : (_y);
}
protected:
double _x;
static const double _y;
};
Что может быть /* SOMETHING */
состояние ?
я хочу вернуться _x
если параметр шаблона void, и вернуть _y
если не. Как это сделать ?
Во-первых, вы ничего не можете вернуть, потому что функция возвращает тип (фиксированный)void
,
Во-вторых, вы можете специализировать эту функцию, чтобы она действовала по-другому, когда Type
является void
:
template<class Type> class MyClass
{
public:
double getValue()
{
return _y;
}
protected:
double _x;
static const double _y;
};
template<>
inline double MyClass<void>::getValue()
{
return _x;
}
Вы можете написать, используя SFINAE:
template<typename Type = void>
class MyClass
{
public:
std::enable_if<std::is_same<Type, void>::value, decltype(_x)> getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return _x;
}
std::enable_if<!(std::is_same<Type, void>::value), decltype(_y)> getValue()
{
return _y;
}
protected:
double _x;
static const double _y;
};
Вы можете использовать динамическое приведение для проверки типов. Динамические приведения возвращают нулевые указатели, если приведение производится к другому типу;
Вот пример.
SomeClass* somePointer = NULL;
somePointer = dynamic_cast<SomeClass*>(someOtherPointer);
if (somePointer)
{
// *someOtherPointer is of type SomeClass
}
else
{
// *someOtherPointer is not of type SomeClass
}
На данный момент главная проблема в том, что вы определили getValue()
как возвращение void
,
Но давайте пропустим это.
Определение функции в C ++ должно быть четко определено. Это означает, что он должен иметь неизменный тип возвращаемого значения, список аргументов и имя. (Я верю, что есть еще пара атрибутов, но здесь это не так важно).
Вы можете перегрузить функцию, чтобы у вас было несколько определений с различными списками аргументов, однако возвращаемый тип должен быть одинаковым для всех функций с одинаковым именем. Вы можете получить другой возвращаемый тип, если используете шаблоны, и возвращаемый тип будет аргументом шаблона.
Теперь, чтобы справиться с разными типами, я считаю, что есть два способа. Одним из них является использование шаблонов и специализаций.
Вы могли бы определить getValue()
как template<T> double getValue();
а затем использовать разные специализации для обработки различных ветвей вашего оригинала getValue
, В вашем примере это будет:
//default case
template<typename T> double MyClass<T>::getValue() { return _y; }
//void case
template<> double MyClass<void>::getValue() { return _x; }
Второй вариант заключается в использовании RTTI механизм, позволяющий определять типы объектов во время выполнения. Код может понравиться почти так же, как ваш. Например.
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (typeid(Type) == typeid(void)) ? (_x) : (_y);
}
Все зависит от того, можете ли вы определить Type во время компиляции или нет. Подход RTTI имеет свои недостатки. Если вы когда-либо хотели обрабатывать больше типов, RTTI позволяет вам сделать это, изменив одну функцию при шаблонном подходе, вам нужно будет добавить другую специализацию. Я думаю, это зависит от ваших предпочтений, какой путь выбрать … и шаблон довольно приятный, когда дело доходит до дизайна.
Редактировать: Oopsies … Я пропустил, что ваш класс templatized Type
, Так что это практически должно удалить RTTI Apporach из вопроса. В любом случае, я оставлю ответ, если кто-нибудь придет сюда с единственным заголовком, так как я считаю, что это все еще верный способ сделать это.
С помощью SFINAE гарантирует, что вся работа выполняется компилятором, в то время как другие опции используют typeid
, dynamic_cast
и т.д., требуют некоторых затрат времени выполнения, которые совершенно не нужны (так как вся информация доступна во время компиляции). На самом деле, это очень плохие примеры того, когда лучше всего использовать такие методы.
Возможное решение SFINAE
template<class Type = void> class MyClass
{
public:
typename std::enable_if< std::is_void<Type>::value, double>::type
getValue() { return _x; }
typename std::enable_if<!std::is_void<Type>::value, double>::type
getValue() { return _y; }
protected:
double _x;
static const double _y;
};