我想知道我是否可以自动推断数组的大小,该数组作为模板参数传递,而不(明确地)传递其大小。
以下代码在g ++ 4.8和clang ++ 3.3上编译无警告(使用-std=c++11 -Wall
)。
#include <iostream>
template<const int* arr>
struct array_container
{
static constexpr int val = arr[1];
array_container() {
std::cout << val << std::endl;
}
// static constexpr int arr_size = ??;
};
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
// array_container<one> array_one;
array_container<two> array_two;
// (void) array_one;
(void) array_two;
return 0;
}
但是,如果我删除main()
中的两个注释符号,我会在两个编译器中出现错误。
现在,这很酷。不知何故,编译器知道数组的大小,尽管const int* arr
的类型是指针。有没有办法得到arr的大小,例如在array_container
完成我的评论?
当然,你不被允许
constexpr std::array<int, 1> one = { 1 }
,或在字符串中使用结束标记,如'\0'
)array_container<1, one> array_one
)的尺寸使用其他模板参数。答案 0 :(得分:1)
C ++ 11标准库的std::extent
标题中的<type_traits>
模板可能就是您想要的:
#include <iostream>
#include <type_traits>
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
std::cout << std::extent<decltype(one)>::value << std::endl;
std::cout << std::extent<decltype(two)>::value << std::endl;
return 0;
}
输出:
1
2
答案 1 :(得分:0)
可能不是,因为SFINAE只发生在直接上下文中,而该错误来自constexpr
中的UB导致编译时错误的要求,我认为这不是立竿见影的。您可以尝试在UB上停止的递归SFINAE,但即使它起作用,您也必须检查标准并希望它不会改变(因为它是相当模糊和新的)。
简单的方法是使用ise函数来推导数组大小,必须将其显式传递给类型,然后将其存储在auto
中。可能不是你想要的。
有些建议允许从值参数中推导出类型参数,因此您可以等待它们。
不是一个可靠的答案,更多的是扩展评论,所以标记为社区维基。
答案 2 :(得分:0)
template<size_t size>
constexpr size_t arraySize ( const int ( &arrayRef ) [size] ) {
return size;
}
int main(){
int A[1];
int B[2];
cout << arraySize(A) << arraySize(B);
return 0;
}
我相信使用数组引用就是你要找的东西。声明数组引用的语法看起来有点像函数指针的语法。此函数模板接受名为arrayRef的数组引用,该引用可防止数组到指针的衰减,从而保留有关数组大小的编译时信息。如您所见,模板参数对编译器是隐式的。请注意,这只能在编译时推断出大小时才有效。有趣的是,这仍然可以在没有命名arrayRef的情况下工作。要使上述模板更有用,您可以添加模板参数以推断出数组的类型。为了清楚起见,我把它留了出来。
答案 3 :(得分:0)
确实有可能。我找到了使用SFINAE的解决方案。如果索引超出范围(本例中的第3行),它基本上会产生替换错误:
template<class C>
static yes& sfinae(typename val_to_type<
decltype(*C::cont::data), *(C::cont::data + C::pos)>::type );
template<class C>
static no& sfinae(C );
完整的源代码位于github。
只有两个缺点: