2015-06-29 6 views
0

Мне нужна прозрачная оболочка вокруг структуры данных, чтобы добавить некоторые свойства. Самый простой что-то вроде этого:Добавить const при доступе к переменной-члену

template<typename T> 
struct Wrapper{ 
    T values; 
} 

Теперь я хочу, чтобы передать это аксессор и держать константность. База будет:

template<class T> 
T& accVal(usigned idx, T* vals){ return vals[idx]; } 
template<class T> 
const T& accVal(usigned idx, const T* vals){ return vals[idx]; } 

template<class T> 
auto 
acc(unsigned idx, T& data) -> decltype(accVal(idx, data.values)) 
{ 
    return accVal(idx, data.values); 
} 

//Example: 
Wrapper<int*> intsWrapped; 
cout << acc(1, intsWrapped); 

Это работает только для не-указателей, скажем, заменить «T *» с структурой, как доступ к data.values ​​отбрасывается константность данных, и я был бы в состоянии манипулировать она как :

void foo(const Wrapper<int*>& bar){ acc(1, bar) = 5; } 

Это опасно в моем приложении.

Итак, как я могу сохранить постоянство? Я пытался что-то вроде этого:

template< class T_Base, typename T_Mem > 
struct GetConstCorrect 
{ 
    template< typename T > 
    struct AddConstVal: std::add_const<T>{}; 

    template< typename T > 
    struct AddConstVal<T&> 
    { 
     using type = std::add_const_t<T> &; 
    }; 

    template< typename T > 
    struct AddConstVal<T*> 
    { 
     using type = std::add_const_t<T>*; 
    }; 

    template< typename T > 
    struct AddConstVal<T* const> 
    { 
     using type = std::add_const_t<T>* const; 
    }; 

    template< typename T > 
    struct AddConstVal<T*&> 
    { 
     using type = std::add_const_t<T>*&; 
    }; 

    template< typename T > 
    struct AddConstVal<T*const &> 
    { 
     using type = std::add_const_t<T>* const &; 
    }; 

    using Base = T_Base; 
    using Mem = T_Mem; 

    static constexpr bool isConst = std::is_const<Base>::value; 
    using type = std::conditional_t< isConst, 
      typename AddConstVal<Mem>::type, 
      Mem 
      >; 
}; 

template< class T_Base, typename T_Mem > 
using GetConstCorrect_t = typename GetConstCorrect< T_Base, T_Mem >::type; 

template< class T_Base, typename T_Mem > 
GetConstCorrect_t< T_Base, T_Mem& > 
getConstCorrect(T_Mem& mem) 
{ 
    return const_cast<GetConstCorrect_t< T_Base, T_Mem& >>(mem); 
} 

И data.values ​​доступа по getConstCorrect (data.values), но это по-прежнему кажется, подвержены ошибкам. (Например, мультипотоп, такой как int **, станет int const not int const **)

Есть ли лучший способ достичь этого?

ответ

2

Пока кто-нибудь не придумает лучшего решения, я думаю, что это ответ: Используйте AddConstVal как рекурсивную метафункцию, которая удаляет все модификаторы один за другим, вызывает себя и считывает модификатор.

template< typename T > 
struct AddConstVal: std::add_const<T>{}; 

template< typename T > 
using AddConstVal_t = typename AddConstVal<T>::type; 

template< typename T > 
struct AddConstVal<T&> 
{ 
    using type = AddConstVal_t<T>&; 
}; 

template< typename T > 
struct AddConstVal<T*> 
{ 
    using type = AddConstVal_t<T>*; 
}; 

template< typename T > 
struct AddConstVal<T const> 
{ 
    using type = AddConstVal_t<T> const; 
}; 

template< typename T > 
struct AddConstVal<T volatile> 
{ 
    using type = AddConstVal_t<T> volatile; 
}; 

template< typename T > 
struct AddConstVal<T []> 
{ 
    using type = AddConstVal_t<T> []; 
}; 

template< typename T, size_t N > 
struct AddConstVal<T [N]> 
{ 
    using type = AddConstVal_t<T> [N]; 
}; 
Смежные вопросы