问题描述
我正在设计一个“ dereferencer” 类,很有趣。
我写了struct
和alias
:
template <class _T>
using deref_type = decltype(*std::declval<_T>());
template <class _T,class _SFINAE>
struct is_derefable : std::false_type {};
template <class _T>
struct is_derefable< _T,deref_type<_T> > : std::true_type
{
using return_type = deref_type<_T>;
};
template<class _T>
using check_derefable = is_derefable<T,deref_type<T>>;
假设有一个类型为T = std::vector<int**>::iterator
的变量,它是被迭代到2级指针中的迭代器,因此具有3级可撤销性。
在这里,我想知道在编译时处任意类型T
的最大“可引用性”。
std::cout << deref_level<std::vector<int**>::iterator>::max << std::endl; // this should prints 3
我认为这类似于在编译时生成序列:Template tuple - calling a function on each element ,但我无法对其进行具体描绘。
这是我尝试过的:
template<class _TF,class _T>
struct derefability {};
template<int _N,class _derefability>
struct deref_level;
template<int _N,class _T>
struct deref_level<_N,derefability<std::false_type,_T>>
{
static const int max = _N;
};
template<int _N,derefability<std::true_type,_T>> :
deref_level<_N + 1,derefability<typename check_derefable<deref_type<_T>>::type,deref_type<_T>>>{};
deref_level<0,derefability<check_derefable<T>::type,T>::max;
但是它不起作用...(编译器说 max 不是tje类的成员)。出了什么问题?
解决方法
这是直接使用SFINAE的递归实现:
template <class T,class = void>
struct deref_level {
enum : std::size_t { value = 0 };
};
template <class T>
struct deref_level<T,decltype(void(*std::declval<T const &>()))> {
enum : std::size_t { value = deref_level<decltype(*std::declval<T const &>())>::value + 1 };
};
,
我不知道您的模板示例出了什么问题,但这是一个使用递归consteval函数的实现:
#include <type_traits>
template<typename T,int N = 0>
consteval int deref_level()
{
if constexpr (std::is_pointer<T>::value) {
typedef typename std::remove_pointer<T>::type U;
return deref_level<U,N + 1>();
} else {
return N;
}
}
int main() {
return deref_level<int****>(); // Returns 4
}
,
经过几天的工作,我能够编写出能够在MSVC13中不会引起错误的代码。
首先,我需要一个功能强大的模块来检查该类型的 可解除引用性 。
由于结构级SFINAE检查失败,因此我根据答案:link采用了另一种方法,该方法使用auto->decltype
表达式从重载函数推导返回类型。 / p>
template<class T>
struct is_dereferenceable
{
private:
template<class _type>
struct dereferenceable : std::true_type
{
using return_type = _type;
};
struct illegal_indirection : std::false_type
{
using return_type = void*;
};
template<class _type>
static auto dereference(int)->dereferenceable<
decltype(*std::declval<_type>())>;
template<class>
static auto dereference(bool)->illegal_indirection;
using dereferenced_result = decltype(dereference<T>(0));
public:
using return_type = typename dereferenced_result::return_type;
static const bool value = dereferenced_result::value;
};
现在我有一个强大的可解除引用性检查器,其余部分变得很容易。
template< class T,class D = typename is_dereferenceable<T>::return_type >
struct dereferenceability;
template< class T >
struct dereferenceability<T,void*>
{
using level = std::integral_constant<int,0>;
};
template< class T,class D >
struct dereferenceability<T,D&>
{
using level = std::integral_constant<int,dereferenceability<D>::level::value + 1>;
};
int main()
{
static_assert(dereferenceability<int>::level::value == 0,"something went wrong");
static_assert(dereferenceability<int****>::iterator>::level::value == 4,"something went wrong");
return 0;
}
我已经在Visual Studio 2013中测试了上面的代码,并且没有发生错误。