检查成员函数时 SFINAE 测试失败

SFINAE-test fails when checking for member function

我尝试实现自己的 SFINAE 测试以确定模板变量的类型,在本例中是标量还是向量:

#include <iostream>
#include <vector>

template <typename...>
using void_t = void;

template <typename, template <typename> class, typename = void_t<>>
struct detect : std::false_type {};

template <typename T, template <typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};

template <typename T>
using toSize_t = decltype(std::declval<T>().size());

template <typename T>
using has_toSize = detect<T, toSize_t>;

int main(void)
{
    std::cout << "Hello World\n";
    std::vector<int> vec_a;
    std::vector<double> vec_b;
    double scal_a;
    int scal_b;
    std::cout << "scal_b is a vector: " << detect<int, has_toSize>{} << '\n';
    return 0;
}

现在,int 肯定没有成员函数 size(),但我仍然得到一个 true 而不是 false 值。为什么?

表达式:

detect<int, has_toSize>{}

很奇怪。

注意,has_toSize 是别名。编写 has_toSize<T> 始终是一个有效的表达式,其中 T 是任意类型。结果 detect 检测到 Op<T>,其中 Ophas_toSize,是一个有效的表达式。所以,输出是 true.

detect的正确使用方法是:

std::cout << has_toSize<int>{} << std::endl;
                       ^^^^^
                     check type

这意味着,您检查一个类型(int 在这种特殊情况下)是否具有 size() 成员函数。

在 C++17 中,您可以使用 is_detected。这将所有 SFINAE 隐藏在一个漂亮的元函数中。调用类似于其他答案。

#include <experimental/type_traits>

template < typename T >
using toSize_t = decltype(std::declval<T>().size());

template < typename T >
using has_toSize = std::experimental::is_detected< toSize_t, T >;

int main()
{
  static_assert( has_toSize<int>::value == false );
}