c++ - SFINAE 检查 operator[] 比我还糊涂?

标签 c++ templates c++14 sfinae c++17

我为 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 错误、一般错误,还是我在某处犯了一个明显的错误?

最佳答案

只需删除 & 并使用 declval 作为 key :

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

Live example at 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,您的检查将不需要默认可构造的 key 。

关于c++ - SFINAE 检查 operator[] 比我还糊涂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39662995/

相关文章:

python - 为什么在使用 Python/C API 时会出现此段错误?

c++ - 将 unsigned int 转换为字节数组并返回

c++ - 如何连接 str 和 int ptr

c++ - 在继承中更改成员类型

c++ - 不鼓励在 C++ 中使用常量吗?

C++ 模板对空构造函数的需求

c++ - 模板特化中的 protected 成员访问错误

c++ - 防止非类型模板参数中的类型违规

c++ - 析构函数异常时返回值的破坏

c++ - 为不同的特征专门化相同的运算符