Чтобы ответить на ваш вопрос о шаблонах (хотя в данном конкретном приложении это не правильное решение по многим причинам):
Причина, по которой вы не работали, как вы писали, заключается в том, что происходит создание экземпляра шаблонаво время компиляции, и единственное, что происходит тогда, это то, что значение std::is_same
вычисляется для аргумента шаблона.Таким образом, в коде для function<solo>
строка
if(std::is_same<T, duo>::value) std::cout<< std::to_string(test.b);
будет иметь вид
if(false) std::cout<< std::to_string(test.b);
, который не компилируется, поскольку в test
нет члена b
.
Чтобы заставить его работать, вам нужно два шаблона и использовать SFINAE для выбора правильного при создании экземпляра шаблона (а поскольку шаблоны функций не могут быть частично специализированными, вам нужно написать что-то вроде следующего, что на самом делеглупый способ записать две перегрузки. Или вы можете полностью специализировать шаблон, но тогда вы не будете использовать if_same
).
template<class T>
typename std::enable_if<!std::is_same<T, duo>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
}
template<class T>
typename std::enable_if<std::is_same<T, duo>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
std::cout<< std::to_string(test.b);
}
Кроме того, обратите внимание, что is_same смотрит на статический тип переменной, так что если у вас есть объект solo&
к duo
, он все равно выберет перегрузку solo
.
Несколько менее глупое использование шаблонов - написать шаблон функции, который может обрабатывать любой тип , который имеет член int b
.При этом используется вспомогательная метафункция (структура, поэтому мы можем использовать частичную специализацию):
template <class T, class = int>
struct has_member_b : std::false_type {};
template <class T>
struct has_member_b<T, decltype(std::declval<T>().b)> : std::true_type {};
template<class T>
typename std::enable_if<has_member_b<T>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
std::cout<< std::to_string(test.b);
}
template<class T>
typename std::enable_if<!has_member_b<T>::value, void>::type function(T test) {
std::cout<< std::to_string(test.a);
}
(обратите внимание, что обе версии предполагают наличие члена a
, в противном случае он не будет компилироваться)