SFINAE检查运营商[]比我更困惑?

xin*_*aiz 3 c++ templates sfinae c++14 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;
}
Run Code Online (Sandbox Code Playgroud)

我正在使用GCC 6.2.0

Coliru

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

Gui*_*cot 8

只需删除&并使用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 {};
Run Code Online (Sandbox Code Playgroud)

在coliru的现场例子

为什么检查S()给出了错误的结果?因为在海湾合作委员会中,它被视为原样0.A std::string可以用指针构造,并且0恰好是空指针常量.

其他编译器不应该S()0在C++ 14中那样对待.

你可以试试自己:

std::map<std::string, std::string> test;

// compile fine, segfault at runtime
auto a = test[0];

// compile error!
auto b = test[2]
Run Code Online (Sandbox Code Playgroud)

检查效果更好,std::declval因为它不是一个0,不是2一个普通的int.奖金,declval您的支票不需要密钥是默认可构造的.

  • 实际上,这是一个错误.在C++ 14中,只有文字零是空指针常量.`S()`不是. (6认同)