使用模板递归检查函数方法是否存在
Recursively check if function method exists using template
出于某些原因,我希望能够做到这一点;
vector<int> p = {1, 2};
vector<vector<int>> q = {p, {0, 1}};
auto t = test(p);
auto u = test(q); // Fails with below implementation
值得注意的是,测试被模板化以接受自定义类,这些类对于一个或两个(目前)维度可能是可迭代的,也可能不是可迭代的。我试图通过检查给定的内容是否具有size
函数来确定该做什么;
template<typename T> struct hasSize {
template<typename U, size_t(U::*)() const> struct SFINAE {};
template<typename U> static char Test(SFINAE<U, &U::size>*);
template<typename U> static int Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};
template<typename iterable> int test(const iterable &x, std::false_type) {
return (int) x;
}
template<typename iterable> int test(const iterable &x, std:: true_type) {
int total = 0;
for(auto &each : x)
total += test(each,
std::integral_constant<bool, hasSize<decltype(each)>::value>());
return total;
}
template<typename iterable> int test(const iterable &view) {
return test(view, std::true_type());
}
在放弃这个答案后,我根据这里给出的答案建立了hasSize,因为这似乎只适用于成员变量,而不适用于函数。我也尝试了第一次讨论中给出的has_const_reference_op
的修改版本,但这也有同样的问题。
给出的错误表明SNIFAE没有第二次应用;
error C2440: 'type cast':
cannot convert from 'const std::vector<int, std::allocator<_Ty>>' to 'int'
note: No user-defined-conversion operator available that can perform this conversion,
or the operator cannot be called
note: see reference to function template instantiation
'int test<iterable>(const iterable &, std::false_type)' being compiled
with iterable = std::vector<int,std::allocator<int>>
但我不知道为什么。
失败的原因是auto&
类型的变量实际上是const std::vector<int>&
类型,iterable
类型是const vector<vector<int>>&
类型,因此当使用decltype
查询时,它会生成一个引用类型,该引用类型无法通过SFINAE检查size
成员函数是否存在。因此,不使用decltype
,只需从iterable
:中读取value_type
即可
total += test(each, std::integral_constant<bool,
hasSize<typename iterable::value_type>::value
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
>());
或者从decltype
:产生的类型中移除引用/常量
total += test(each, std::integral_constant<bool,
hasSize<typename std::decay<decltype(each)>::type>::value
// ~~~~~~~~~^
>());
首先,这对于一般的test()
:来说不是正确的做法
template<typename iterable> int test(const iterable &view) {
return test(view, std::true_type());
}
因为一般来说test
是不可迭代的——这就是我们需要测试的!因此,我们将把它转发到命名空间中的一系列三个函数中,这样我们就可以利用ADL来找到我们需要找到的一切:
namespace adl {
struct helper {};
template<typename iterable>
int test(helper, const iterable &x, std::false_type) {
return (int) x;
}
template<typename iterable>
int test(helper, const iterable &x, std:: true_type) {
int total = 0;
for(auto &each : x) {
// this calls the general one
total += test(helper{}, each);
}
return total;
}
template <typename iterable>
int test(helper, const iterable& x) {
return test(helper{}, x, std::integral_constant<bool, hasSize<iterable>::value>{});
}
}
template<typename iterable>
int test(const iterable &view) {
return test(adl::helper{}, view);
}
我们需要ADL,这样每个函数都可以找到彼此。
请注意,最好编写产生类型的类型特征,而不仅仅是值。我们是否写了这样的东西:
template <class T, class = void>
struct hasSize : std::false_type { };
template <class T>
struct hasSize<T, void_t<decltype(std::declval<T const&>().size())>>
: std::true_type { };
那么我们的测试仪过载可能会短得多:
template <typename iterable>
int test(helper, const iterable& x) {
return test(helper{}, x, hasSize<iterable>{});
}
这可能在VS2013上不起作用,但您仍然可以在hasSize
中添加type
typedef。
相关文章:
- 如何在 c++ 的类中递归调用函数方法?
- 通过构造函数方法输出的类到类类型转换是 5500 为什么不是 5555
- 在 *.cpp 文件中实现的 c++ 函数/方法永远不会内联扩展吗?
- 如果子类中没有构造函数方法,则错误"no matching function for call to 'LGame::LGame(String&)'"
- 指向类中函数方法的指针不起作用
- 如何发送通过绑定到函数/方法创建的函数对象?
- 编译错误,未创建函数/方法! 对于 brms 模型
- 对静态重载(类)函数/方法的调用是不明确的
- 复制构造函数方法的用法
- C/C++ 函数/方法与 Java 的公开
- std ::函数方法参考无法将dword投入到dword64
- 链表的析构函数方法
- 为什么在类构造函数方法中,std::string 参数在调试时显示不同的结果?
- 我的构造函数方法不接受参数(DirectX / Windows)
- 当函数/方法应该要求 * 或 &
- 带有常量构造函数参数的C++变量构造函数方法
- 使用模板递归检查函数方法是否存在
- 如何通过析构函数方法删除对象(类)
- 为什么在 Java 和 C++ 中不允许隐藏虚拟函数/方法?
- 在构造函数方法中返回一个子类