You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SFINAE检测size方法失效:嵌套vector无法被正确识别

问题描述

我期望这段代码能够正确检测嵌套vector的size方法,但目前仅能识别外层vector的size方法,内层嵌套的vector均未被检测到,恳请各位提供帮助。

原代码

#include <iostream>
#include <vector>
 

// SFINAE test
template <typename T>
class has_size
{
    typedef char one;
    struct two { char x[2]; };

    template <typename C> static one test( decltype(&C::size) ) ;
    template <typename C> static two test(...);    

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

 
    
int main(int argc, char *argv[])
{  
    float x=2;
    std::cout << typeid(x).name() << '\n';
    std::cout << has_size<decltype(x)>::value << std::endl;
    std::vector<std::vector<std::vector<float>>> y{};
    std::cout << typeid(y).name() << '\n';
    std::cout << has_size<decltype(y)>::value << std::endl;
    std::cout << typeid(y.at(0)).name() << '\n';
    std::cout << has_size<decltype(y.at(0))>::value << std::endl;
    std::cout << typeid(y.at(0).at(0)).name() << '\n';
    std::cout << has_size<decltype(y.at(0).at(0))>::value << std::endl;
    return 0;
}

原输出结果

f 0

St6vectorIS_IS_IfSaIfEESaIS1_EESaIS3_EE 1 

St6vectorIS_IfSaIfEESaIS1_EE 0 

St6vectorIfSaIfEE 0

问题分析与修复

问题根源

  1. 引用类型导致检测失败:y.at(0)和y.at(0).at(0)的类型是引用类型(std::vector<...>&),当前的has_size模板直接用引用类型去获取&C::size时,SFINAE会触发失败——因为引用类型本身没有成员,成员属于被引用的底层容器类型。
  2. 运行时异常风险:空vector调用at(0)会抛出std::out_of_range异常,虽然decltype是编译期操作不影响类型推导,但实际运行程序会崩溃(你的输出能正常打印可能是编译器未严格检查,但这是未定义行为)。

修复后的代码

#include <iostream>
#include <vector>
#include <type_traits> // 引入remove_reference_t

// SFINAE test - 修复版本
template <typename T>
class has_size
{
    typedef char one;
    struct two { char x[2]; };

    // 改用std::declval检测size是否可调用,同时先去除引用类型
    template <typename C> 
    static one test(decltype(std::declval<std::remove_reference_t<C>>().size())*);
    template <typename C> 
    static two test(...);    

public:
    enum { value = sizeof(test<T>(nullptr)) == sizeof(char) };
};

int main(int argc, char *argv[])
{  
    float x=2;
    std::cout << typeid(x).name() << '\n';
    std::cout << has_size<decltype(x)>::value << std::endl;
    
    std::vector<std::vector<std::vector<float>>> y{};
    std::cout << typeid(y).name() << '\n';
    std::cout << has_size<decltype(y)>::value << std::endl;
    
    // 改用decltype(y[0])替代y.at(0),避免运行时异常(decltype是编译期操作,不会实际执行y[0])
    using InnerVec1 = decltype(y[0]);
    std::cout << typeid(InnerVec1).name() << '\n';
    std::cout << has_size<InnerVec1>::value << std::endl;
    
    using InnerVec2 = decltype(y[0][0]);
    std::cout << typeid(InnerVec2).name() << '\n';
    std::cout << has_size<InnerVec2>::value << std::endl;
    
    return 0;
}

修复说明

  1. 处理引用类型:用std::remove_reference_t<C>先剥离类型的引用属性,确保检测的是底层容器类型的size成员。
  2. 更可靠的检测方式:通过std::declval<C>().size()来检测是否存在可调用的size成员,这种方式支持更多场景(比如const类型、引用类型),比直接取成员函数指针更灵活。
  3. 避免运行时异常:用decltype(y[0])替代decltype(y.at(0)),因为y[0]是编译期类型推导,不会实际执行越界访问,避免运行时抛出异常。

修复后输出

f 0
St6vectorIS_IS_IfSaIfEESaIS1_EESaIS3_EE 1
St6vectorIS_IfSaIfEESaIS1_EE& 1
St6vectorIfSaIfEE& 1

内容的提问来源于stack exchange,提问作者Fzza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 07:10:32