检查类型是否在 C++ 中定义了 [][]

Checking if a type has [][] defined in C++

本文关键字:定义 C++ 类型 是否 检查      更新时间:2023-10-16

我正在编写一个构造函数,并希望为任何实现整型参数[][]的类型定义它。换句话说,T必须定义T[]类型,并且在T本身上使用[]时返回的类型也[]定义,例如,允许调用T[2][3]

我知道如何使用此处的答案检查重载运算符是否存在,该答案显示了operator==的方法,这可以很容易地扩展到我的情况。

但是,问题是我想检查T[]的类型是否也具有operator[]

如前所述,我还需要检查重载operator[]接受的参数是否包含任何整数类型,因此operator[](const T& i)会有一些T,从而产生std::is_integral<T>::value为真。

显然,我的目的是允许接口接受任何行为类似于矩阵的东西,并具有访问其元素的标准方法。

你可以 sfinae 例如在std::declval<const T>()[1][1]

template<class T, class = decltype(std::declval<const T&>()[1][1])>
void foo(const T& matrix){
    ...
}

或:

template<class T, decltype(void(std::declval<const T&>()[1][1]),true)=true>
void foo(const T& matrix){
  ...
}

如果您选择了多个 SFINAE foo重载,则效果更好。

*(我在手机上,所以我还没有用编译器检查过。

这里有两种方法可以做到这一点。第一个不使用任何外部库,并且使用与您发布的链接答案相同的想法。第二个使用boost.hana库中的功能。

#include <iostream>
#include <type_traits>
#include <vector>
#include <boost/hana/type.hpp>
// SFINAE trick, not using any external libraries
template <class X>
class check {
    // this overload will be selected whenever X[][] is defined
    template <class T>
    static auto call(T*) -> decltype(std::declval<T>()[1][1], std::true_type{});
    // and this when X[][] is not defined
    template <class T>
    static std::false_type call(...);
public:
    using type = decltype (call<X>(0));
};
// using boost.hana library
template <class X>
class hana_check {
    static auto call() {
        auto test = boost::hana::is_valid([](auto&& x) -> decltype (x[1][1]) {});
        return decltype(test(std::declval<X>())){};
    }
public:
    using type = decltype (call());
};
using test_type1 = check<int>::type; // false_type
using test_type2 = check<std::vector<std::vector<int>>>::type; // true_type
using test_type3 = hana_check<double>::type; // false_type
using test_type4 = hana_check<std::vector<std::vector<double>>>::type; // true_type
int main() {
    std::cout << test_type1::value << std::endl;
    std::cout << test_type2::value << std::endl;
    std::cout << test_type3::value << std::endl;
    std::cout << test_type4::value << std::endl;
}