如何使用模板找到参数 T 的最大可取消引用级别
How to find maximum dereferenceable-level of the parameter T using template
我正在设计一个 “解引用器” class,只是为了好玩。
我写了一些 struct
s 和 alias
s :
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
的变量,它是解引用为二级指针的迭代器,因此具有三级解引用能力。
在这里,我想知道任意类型 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, class _T>
struct deref_level<_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 class 的成员)出了什么问题?
下面是直接使用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 中不会导致错误的代码。
首先,我需要一个健壮的模块来检查类型的解引用能力。
由于 struct-level SFINAE 检查失败,我采用了另一种方法,从 重载函数 和 auto->decltype
表达式中推导出 return 类型,基于答案:link
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;
};
现在我有一个健壮的dereferenceability-checker,剩下的部分变得容易多了。
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 年测试了上面的代码,没有发生错误。
我正在设计一个 “解引用器” class,只是为了好玩。
我写了一些 struct
s 和 alias
s :
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
的变量,它是解引用为二级指针的迭代器,因此具有三级解引用能力。
在这里,我想知道任意类型 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, class _T>
struct deref_level<_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 class 的成员)出了什么问题?
下面是直接使用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 中不会导致错误的代码。
首先,我需要一个健壮的模块来检查类型的解引用能力。
由于 struct-level SFINAE 检查失败,我采用了另一种方法,从 重载函数 和 auto->decltype
表达式中推导出 return 类型,基于答案:link
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;
};
现在我有一个健壮的dereferenceability-checker,剩下的部分变得容易多了。
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 年测试了上面的代码,没有发生错误。