SFINAE检查操作员[]比我更困惑

SFINAE check for operator[] is more confused than I am?

本文关键字:检查 操作员 SFINAE      更新时间:2023-10-16

我为operator[]写了一个简单的检查,但是has_subscript_op结构模板实例化选择了错误的重载:

#include <iostream>
#include <type_traits>
#include <string>
#include <map>
template<class, class, class = void>
struct has_subscript_op : std::false_type
{ };
template<class T, class S>
struct has_subscript_op<T, S, std::void_t<decltype(&std::declval<T>()[S()])>> : std::true_type
{ };
int main()
{
    //true, nice
    std::cout << "int[][int]: " << has_subscript_op<int[], int>::value << std::endl;
    //false, nice
    std::cout << "int[][float]: " << has_subscript_op<int[], float>::value << std::endl;
    //true, nice
    std::cout << "std::string[int]: " << has_subscript_op<std::string, int>::value << std::endl;
    //true, WAT?
    std::cout << "std::map<std::string, std::string>[int]: " << has_subscript_op<std::map<std::string, std::string>, int>::value << std::endl;
}

使用GCC 6.2.0

Coliru

这是GCC bug,一般bug,还是我在某个地方犯了一个明显的错误?

去掉&,用declval作为键:

template<class T, class S>
struct has_subscript_op<T, S, std::void_t<decltype(std::declval<T>()[std::declval<S>()])>> : std::true_type {};

coliru的实例

为什么S()的检查给出了错误的结果?因为在GCC中,它被认为是0std::string可以用指针构造,而0恰好是一个空指针常量。

其他编译器不应将S()视为c++ 14中的0

你可以自己试试:

std::map<std::string, std::string> test;
// compile fine, segfault at runtime
auto a = test[0];
// compile error!
auto b = test[2]

检查std::declval更好,因为它不是0,也不是2,而是普通的int。另外,使用declval,您的检查将不需要密钥是默认可构造的。