我正在玩一些使用c ++ 11的玩具代码来弄清楚事情是如何运作的.在此期间,我遇到了以下问题,简化为:
template <int x, int y>
class add {
public:
static constexpr int ret = x + y;
};
constexpr int addFunc(const int x, const int y) {
return add<x,y>::ret;
}
int main() {
const int x = 1;
const int y = 2;
cout << add<x,y>::ret << endl; // Works
cout << addFunc(1,2) << endl; // Compiler error
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用GCC 4.8.1并且输出为:
'x'不是模板参数中的常量表达式,用于'int'类型
'y'不是类型'int'的模板参数中的常量表达式
我试图计算的两种方式之间究竟有什么区别add::ret?这两个值都应该在编译时可用.
虽然我之前使用过这样的代码,但很明显编译器有足够的信息可以工作,但我真的不明白为什么这会编译:
template <class T, class I>
auto foo(const T& t, I i) {
return std::get<i>(t);
}
int main()
{
std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
实例:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5.
似乎可以同时使用gcc和clang.的事情是,同时integral_constant具有constexpr转换所存储的整数,constexpr成员函数隐式地把对象本身作为参数,并且因此不能被用在这样的函数constexpr的上下文,除非我们正在呼叫的成员函数的对象本身可以作为被处理constexpr.
这里i是一个传递给的参数foo,因此i绝对不能被视为constexpr.然而,确实如此.一个更简单的例子:
template <class I>
void foo(I i) {
constexpr std::size_t j = i;
}
Run Code Online (Sandbox Code Playgroud)
这也是编译,只要std::integral_constant<std::size_t, 0>{}传递给foo.
我觉得我错过了一些关于constexpr规则的明显内容.无状态类型或其他类型是否有例外?(或者,也许是两个主要编译器中的编译器错误?这个代码似乎适用于clang 5和gcc 7.2).
编辑:答案已经发布,但我认为这还不够.特别是,鉴于最后的定义foo,为什么:
foo(std::integral_constant<std::size_t, …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
static constexpr int make_const(const int i){
return i;
}
void t1(const int i)
{
constexpr int ii = make_const(i); // error occurs here (i is not a constant expression)
std::cout<<ii;
}
int main()
{
t1(12);
}
Run Code Online (Sandbox Code Playgroud)
为什么我在make_const调用时出错?
UPDATE
但是这个有效:
constexpr int t1(const int i)
{
return make_const(i);
}
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
template<int i>
constexpr bool do_something(){
return i;
}
constexpr int t1(const int i)
{
return do_something<make_const(i)>(); // error occurs here (i is not a constant expression)
}
Run Code Online (Sandbox Code Playgroud) 考虑以下功能:
template <size_t S1, size_t S2>
auto concatenate(std::array<uint8_t, S1> &data1, std::array<uint8_t, S2> &data2) {
std::array<uint8_t, data1.size() + data2.size()> result;
auto iter = std::copy(data1.begin(), data1.end(), result.begin());
std::copy(data2.begin(), data2.end(), iter);
return result;
}
int main()
{
std::array<uint8_t, 1> data1{ 0x00 };
std::array<uint8_t, 1> data2{ 0xFF };
auto result = concatenate(data1, data2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用clang 6.0编译时,使用-std = c ++ 17,此函数无法编译,因为数组上的size成员函数不是constexpr,因为它是一个引用.错误消息是这样的:
错误:非类型模板参数不是常量表达式
当参数不是引用时,代码按预期工作.
我想知道为什么会这样,因为size()实际上返回一个模板参数,它几乎不再是const.参数是否是参考不应该有所作为.
我知道我当然可以使用S1和S2模板参数,该功能仅仅是问题的简短说明.
标准中有什么吗?我很惊讶地发现了编译错误.