SFINAE为什么我没有检测到std :: vector的下标运算符?

时间:2019-06-20 22:27:45

标签: c++ sfinae

我写了一些模板元废话来检测类方法是否存在。

模板结构has_subscript是专用的,因此,如果第一个模板参数具有下标运算符,则第二个模板参数为void。如果找到下标运算符,则使用专业化版本,否则SFINAE默认为非专业化版本。

我有用于简单struct foo的代码(它的模板化只是为了更好地匹配std::vector),但是意外地失败了,并显示std::vector

演示链接https://godbolt.org/z/5-QzAp

#include <type_traits>
#include <iostream>
#include <vector>
using namespace std;

template <typename>
struct void_wrap
{ using type = void; };


template <typename T, typename = void>
struct has_subscript
{
  static constexpr bool value = false;
};

template <typename T>
struct has_subscript <T, typename void_wrap<typename result_of<decltype(&T::operator[])(T,int)>::type>::type >
{
  static constexpr bool value = true;
};

template <typename T>
struct foo
{
  double operator[](size_t x){return 0.0;}
};

int main()
{
  cout << has_subscript<foo<int>>::value;
  cout << has_subscript<vector<int>>::value;
}

2 个答案:

答案 0 :(得分:4)

它与您尝试推导operator[]的方式有关,它适用于foo,但不适用于std::vector,因为它过载了。

由于typename result_of<decltype(&T::operator[])(T,int)>::type不明确,因此无法使用表达式&T::operator[]

如果您使用decltype(std::declval<T&>()[int()]),它将按预期工作(请参见here)。

答案 1 :(得分:0)

您可以从库基础知识TS v2 中使用std::is_detected

#include <type_traits>
#include <experimental/type_traits>
#include <vector>

template<typename T>
using bracket_op_t = decltype( std::declval<T&>()[0] );

template<typename T>
constexpr bool has_bracket_op = std::experimental::is_detected<bracket_op_t, T>::value;

int main()
{
    // static_assert(has_bracket_op<int>, ""); // fails to compile
    static_assert(has_bracket_op<std::vector<int>>, "");
}

LIVE DEMO