如何检查下标运算符的存在? [英] How to check for the existence of a subscript operator?
问题描述
我想写一个类型特征,它使用SFINAE来检查类型是否存在下标表达式.当可能使用下标表达式时,我下面的最初尝试似乎可行,但是当不使用方括号运算符时,我的以下尝试不可行.
I want to write a type trait which uses SFINAE to check a type for the existence of a subscript expression. My initial attempt below seems to work when the subscript expression is possible but does not work when the bracket operator does not exist.
#include <iostream>
#include <vector>
#include <cassert>
template<class T, class Index>
struct has_subscript_operator_impl
{
template<class T1,
class Reference = decltype(
(*std::declval<T*>())[std::declval<Index>()]
),
class = typename std::enable_if<
!std::is_void<Reference>::value
>::type>
static std::true_type test(int);
template<class>
static std::false_type test(...);
using type = decltype(test<T>(0));
};
template<class T, class Index>
using has_subscript_operator = typename has_subscript_operator_impl<T,Index>::type;
struct doesnt_have_it {};
struct returns_void
{
void operator[](int) {}
};
struct returns_int
{
int operator[](int) { return 0; }
};
int main()
{
std::cout << "has_subscript_operator<doesnt_have_it,int>: " << has_subscript_operator<doesnt_have_it,int>::value << std::endl;
assert((!has_subscript_operator<doesnt_have_it,int>::value));
std::cout << "has_subscript_operator<returns_void,int>: " << has_subscript_operator<returns_void,int>::value << std::endl;
assert((!has_subscript_operator<returns_void,int>::value));
std::cout << "has_subscript_operator<returns_int,int>: " << has_subscript_operator<returns_int,int>::value << std::endl;
assert((has_subscript_operator<returns_int,int>::value));
std::cout << "has_subscript_operator<int*,int>: " << has_subscript_operator<int*,int>::value << std::endl;
assert((has_subscript_operator<int*,int>::value));
std::cout << "has_subscript_operator<std::vector<int>,int>: " << has_subscript_operator<std::vector<int>,int>::value << std::endl;
assert((has_subscript_operator<returns_int,int>::value));
return 0;
}
clang-3.4
的输出:
$ clang -std=c++11 -I. -lstdc++ test_has_subscript_operator.cpp
test_has_subscript_operator.cpp:10:14: error: type 'doesnt_have_it' does not provide a subscript operator
(*std::declval<T*>())[std::declval<Index>()]
^~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
test_has_subscript_operator.cpp:25:1: note: in instantiation of template class 'has_subscript_operator_impl<doesnt_have_it, int>' requested here
using has_subscript_operator = typename has_subscript_operator_impl<T,Index>::type;
^
test_has_subscript_operator.cpp:41:66: note: in instantiation of template type alias 'has_subscript_operator' requested here
std::cout << "has_subscript_operator<doesnt_have_it,int>: " << has_subscript_operator<doesnt_have_it,int>::value << std::endl;
^
1 error generated.
我该如何解决我的 has_subscript_operator
,使其对所有类型都正确运行?
How can I fix my has_subscript_operator
such that it works correctly for all types?
推荐答案
SFINAE仅在直接上下文中发生替换失败时才起作用.实例化成员函数模板 test
时,模板参数 Index
就是已知的,因此您会得到一个硬错误,而不是替代失败.
SFINAE only works when substitution failure happens in the immediate context. The template parameter Index
is already known by the time the member function template test
is being instantiated, so instead of substitution failure you get a hard error.
解决此问题的技巧是通过向 test
添加一个附加的模板类型参数并将其默认为 Index
来再次推断 Index
.
The trick to working around this is to deduce Index
again by adding an additional template type parameter to test
and default it to Index
.
template<class T1,
class IndexDeduced = Index, // <--- here
class Reference = decltype(
(*std::declval<T*>())[std::declval<IndexDeduced>()] // and use that here
),
class = typename std::enable_if<
!std::is_void<Reference>::value
>::type>
static std::true_type test(int);
现在您的代码可以正常工作了.
Now your code works as intended.
这篇关于如何检查下标运算符的存在?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!