C++ Как обратиться к полю шаблона структуры по номеру в compile-time
template <class _Ty, class _Alloc = _STD allocator<_Ty>>
struct whisker {
public:
enum class dir: uint8_t {
BL = 0, // поле base_left;
BR = 1, // поле base_right;
HL = 2, // поле hand_left;
HR = 3 // поле hand_right;
};
public:
_Ty val;
whisker* base_left;
whisker* base_right;
whisker* hand_right;
whisker* hand_left;
// Тут нужна функция, которая будет возвращать значение поля по его номеру.
// Но она должна работать в compile-time, что-то вроде такого
template <whisker::dir index>
whisker* at();
template <whisker::dir index == whisker::dir::BL>
whisker* at(){
return base_left;
}
template <whisker::dir index == whisker::dir::HR>
whisker* at(){
return hand_right;
}
}
может вызываться, например, так:
int main(){
whisker* wh;
auto wh_base_left = wh.at<whisker::dir::BL>;
auto wh_hand_right = wh.at<whisker::dir::HR>;
}
- Как это сделать?
- Или я вообще выбрал неправильный путь?
- Если так неправильно, то как написать эту функцию, чтобы не было ветвлений if/else
Очень жду ваших ответов <3
Ответы (2 шт):
Видимо template <whisker::dir index == whisker::dir::BL> было попыткой реализовать специализацию для функции. Однако даже если бы синтаксис был верным, специализация для функции запрещена внутри класса. Однако даже если бы специализация функции была вынесена в пространство имен, специализация функции-члена класса не разрешается без специализации самого класса. Однако даже если добавить отдельный класс со статическим методом, который бы специализировался снаружи, использование параметра не-типа, зависящего от других параметров, не разрешается. Поэтому чтобы это все заработало надо будет еще написать тип-обертку.
#include <cstdint>
template<class x_T, class x_Alloc = void> struct
t_Whisker;
template<class x_T, class x_Alloc, typename t_Whisker<x_T, x_Alloc>::t_Dir x_dir> struct
t_TypeWrapper;
template<typename x_TypeWrapper> class
t_Dispatcher;
template <class x_T, class x_Alloc> struct
t_Whisker
{
template<typename xx_TypeWrapper> friend class
t_Dispatcher;
public:
enum class t_Dir: ::std::uint8_t
{
bl = 0 // поле base_left;
, br = 1 // поле base_right;
, hl = 2 // поле hand_left;
, hr = 3 // поле hand_right;
};
public:
x_T m_val;
t_Whisker * m_base_left;
t_Whisker * m_base_right;
t_Whisker * m_hand_right;
t_Whisker * m_hand_left;
// Тут нужна функция, которая будет возвращать значение поля по его номеру.
// Но она должна работать в compile-time, что-то вроде такого
template <t_Dir x_dir>
t_Whisker * at(void)
{
return t_Dispatcher<t_TypeWrapper<x_T, x_Alloc, x_dir>>::Fetch(*this);
}
};
template<class x_T, class x_Alloc> class
t_Dispatcher<t_TypeWrapper<x_T, x_Alloc, t_Whisker<x_T, x_Alloc>::t_Dir::bl>> final
{
public: static t_Whisker<x_T, x_Alloc> *
Fetch(t_Whisker<x_T, x_Alloc> & self)
{
return self.m_base_left;
}
};
int main()
{
t_Whisker<int> wh{};
wh.at<t_Whisker<int>::t_Dir::bl>();
}
Не буду спорить, что теория не позволяет такое.
Но - just for info, не более того - конкретный компилятор VC++ (проверял на 2019 и 2017 с последними обновлениями) (а по некоторым признакам, код предназначен для VC++), такую специализацию съедает (если, конечно, убрать очевидные, не относящиеся к вопросу ошибки):
template <class _Ty, class _Alloc = _STD allocator<_Ty>>
struct whisker {
public:
enum class dir: uint8_t {
BL = 0, // поле base_left;
BR = 1, // поле base_right;
HL = 2, // поле hand_left;
HR = 3 // поле hand_right;
};
public:
_Ty val;
whisker* base_left;
whisker* base_right;
whisker* hand_right;
whisker* hand_left;
// Тут нужна функция, которая будет возвращать значение поля по его номеру.
// Но она должна работать в compile-time, что-то вроде такого
template <whisker::dir index>
whisker* at();
template <>
whisker* at<whisker::dir::BL>(){
cout << "Left\n";
return base_left;
}
template <>
whisker* at<whisker::dir::HR>(){
cout << "Right\n";
return hand_right;
}
};
int main(){
whisker<int>* wh;
auto wh_base_left = wh->at<whisker<int>::dir::BL>();
auto wh_hand_right = wh->at<whisker<int>::dir::HR>();
}