使用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.
错误原因分析
第一次错误:
remove_reference是模板类,必须通过::type获取它推导后的类型;std::extent的结果是一个编译期常量,需要通过::value访问,而非直接使用模板本身。
原写法既没获取remove_reference的目标类型,也没访问extent的value成员,导致语法错误。
第二次错误:
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
相关产品推荐
相关产品推荐

