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

使用std::extent处理模板数组时的编译错误排查与解决

关于std::extent编译期检查数组大小的错误分析与解决

问题代码

//classA.h

#include <type_traits>
#include <cstddef>
#include <iostream>

using std::is_same;
using std::extent;
using std::remove_reference;
using std::size_t;
using std::cout;
using std::endl;

template<typename T> class A;
template<typename T>
using array2As = A<T>[2];

template<typename T> 
void doSomething (const array2As<T>&);

template<typename T>
class A{
  public:
  A(T);
  private:
  friend void doSomething<>(const array2As<T>&);
  A()=delete;
  A(const A&)=delete; 
  A& operator=(const A&)=delete;
  T elem;
};

template<typename T>
A<T>::A(T elem){
  static_assert(is_same<T,int>::value || is_same<T,double>::value, "Compilation error: type must be int or double");
  this->elem = elem;
}

template<typename T> void doSomething (const array2As<T>& a){

   static_assert(2 == extent<remove_reference<decltype(a)>>, "Compilation error: array must have exactly 2 elements");

//static_assert(2 == extent<a>, "Compilation error: array must have exactly 2 elements");
  
  const auto& obj1 = a[0];
  cout << obj1.elem << endl;
  const auto& obj2 = a[1];
  cout << obj2.elem << endl;
 return;
}

#include "classA.h"

int main (){
 
 array2As<int> a = {A(5),A(7)};
 doSomething<int>(a);
 array2As<double> b = {A(1.2),A(6.3)};
 doSomething<double>(b);

 return 0;
}

编译报错信息

第一次报错(使用未修正的extent行)

In file included from main.cpp:1:
classA.h: In function ‘void doSomething(const A<T> (&)[2])’:
classA.h:42:60: error: expected primary-expression before ‘,’ token
   42 |    static_assert(2 == extent<remove_reference<decltype(a)>>, "Compilation error: array must have exactly 2 elements");
      |                                                            ^
compilation terminated due to -Wfatal-errors.

第二次报错(改用注释行)

In file included from main.cpp:1:
classA.h: In function ‘void doSomething(const A<T> (&)[2])’:
classA.h:43:31: error: type/value mismatch at argument 1 in template parameter list for ‘template<class, unsigned int <anonymous> > struct std::extent’
   43 |    static_assert(2 == extent<a>, "Compilation error: array must have exactly 2 elements");
      |                               ^
compilation terminated due to -Wfatal-errors.

错误原因分析

  1. 第一次错误:

    • remove_reference是模板类,必须通过::type获取它推导后的类型;
    • std::extent的结果是一个编译期常量,需要通过::value访问,而非直接使用模板本身。
      原写法既没获取remove_reference的目标类型,也没访问extent的value成员,导致语法错误。
  2. 第二次错误:
    std::extent的模板参数要求传入类型,但代码中直接传入了变量a,属于类型/值不匹配的错误。

修正后的代码

//classA.h

#include <type_traits>
#include <cstddef>
#include <iostream>

using std::is_same;
using std::extent;
using std::remove_reference;
using std::remove_reference_t; // C++14及以上可用
using std::size_t;
using std::cout;
using std::endl;

template<typename T> class A;
template<typename T>
using array2As = A<T>[2];

template<typename T> 
void doSomething (const array2As<T>&);

template<typename T>
class A{
  public:
  A(T);
  private:
  friend void doSomething<>(const array2As<T>&);
  A()=delete;
  A(const A&)=delete; 
  A& operator=(const A&)=delete;
  T elem;
};

template<typename T>
A<T>::A(T elem){
  static_assert(is_same<T,int>::value || is_same<T,double>::value, "Compilation error: type must be int or double");
  this->elem = elem;
}

template<typename T> void doSomething (const array2As<T>& a){
   // C++14及以上简化写法
   static_assert(2 == extent<remove_reference_t<decltype(a)>>::value, "Compilation error: array must have exactly 2 elements");
   
   // C++11兼容写法
   // static_assert(2 == extent<typename remove_reference<decltype(a)>::type>::value, "Compilation error: array must have exactly 2 elements");
  
  const auto& obj1 = a[0];
  cout << obj1.elem << endl;
  const auto& obj2 = a[1];
  cout << obj2.elem << endl;
 return;
}

#include "classA.h"

int main (){
 
 array2As<int> a = {A(5),A(7)};
 doSomething<int>(a);
 array2As<double> b = {A(1.2),A(6.3)};
 doSomething<double>(b);

 return 0;
}

补充说明

  • decltype(a)得到的是const array2As<T>&(即const A<T>(&)[2]),remove_reference_t(或remove_reference<...>::type)会去掉引用,得到数组类型const A<T>[2];
  • std::extent提取数组的维度大小,通过::value获取编译期常量;
  • 实际上代码已经通过array2As<T>限定了数组大小为2,这个static_assert更多是演示用法;如果要让doSomething接受任意数组并检查大小,可以修改模板为:
    template<typename T, size_t N> 
    void doSomething(const A<T>(&a)[N]){
        static_assert(N == 2, "Compilation error: array must have exactly 2 elements");
        // ... 原有逻辑
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 08:06:01