Closed YiRanMushroom closed 9 months ago
我自己在写程序的时候发现,concept的判断时间是在定义处,而不是在使用处,换言之,如果先定义了一个concept,之后写了一些代码,影响了concept判定条件,即使在之后使用这个concept,依然会按照修改之前的结果判定,这个是正常的吗。如果是正常的,是否应该强调一下?
举个例子,没看明白要表达什么,请详细描述自己的想法。
template<typename T>
concept is_printable_c = requires(T t){
std::cout << t;
};
定义了一个concept。
template<typename T, size_t N>
std::ostream &operator<<(std::ostream &out, const std::array<T, N> &arr)
requires is_printable_c<T> {
out << "[";
for (int i = 0; i < N - 1; i++)
out << arr[i] << ", ";
out << arr[N - 1] << "]";
return out;
}
重载了std::ostream&, std::array&运算符。
调用语句
std::array<int, 5> b{1, 2, 3, 4, 5};
std::cout<<is_printable_c<decltype(b)>;
-> 0
新定义一个concept:
template<typename T>
concept is_printable_after_overloading_c = requires(T t){
std::cout << t;
};
调用语句
std::cout<<is_printable_after_overloading_c<decltype(b)>;
-> 1
这两个concept虽然看着内容相同,但是在不同时间定义造成了判段结果不同。
我能算出你大概要表达什么,但是你是不是不会 markdown?
template concept is_printable_c = requires(T t){ std::cout << t; };
定义了一个concept。
template<typename T, size_t N> std::ostream &operator<<(std::ostream &out, const std::array<T, N> &arr) requires is_printable_c { out << "["; for (int i = 0; i < N - 1; i++) out << arr[i] << ", "; out << arr[N - 1] << "]"; return out; }
重载了std::ostream&, std::array&运算符。
调用语句 std::array<int, 5> b{1, 2, 3, 4, 5};
std::cout<<is_printable_c<decltype(b)>; -> 0
新定义一个concept: template concept is_printable_after_overloading_c = requires(T t){ std::cout << t; };
调用语句 std::cout<<is_printable_after_overloading_c<decltype(b)>; -> 1
这两个concept虽然看着内容相同,但是在不同时间定义造成了判段结果不同。
这本质上是因为编译器会缓存常量求值的结果,编译器认为任意两个相同的模板实例化总是应该具有相同的结果。所以在第一次求值之后,会缓存结果。之后的求值都会使用第一次求值的结果替代。所以和第一次模板实例化的位置有关。
详细的讨论参考:
这个问题在上古年代就说过,只是我觉得偏,懒得做视频,我在外面过年,手机扣字没办法为你展示更多东西。
你能意识到这个问题很好,并且提出来了,你有自己的思考,再说。
但是你的语法格式让我绷不住,尤其我手机看,即使是修改后,而且你应该附带网页运行的链接,而不是打算让我们测试自己看,不方便我们,以及其他人观看和了解你的问题。
如果在不同位置求值约束满足条件结果不同,则程序非良构不要求诊断。这个设计来自 P2104R0。
更严谨的编译器可能应该报错。虽然不报错也没问题。
https://godbolt.org/z/MW7crn7xY 这个是可供测试的代码
如果在不同位置求值约束满足条件结果不同,则程序非良构不要求诊断。这个设计来自 P2104R0。
更严谨的编译器可能应该报错。虽然不报错也没问题。
简单明了。
就是说这种写法本身是有问题的?不应该在concept定义后再更改一些值使concept判定会出现不同结果。
就是说这种写法本身是有问题的?不应该在concept定义后再更改一些值使concept判定会出现不同结果。
不应该依赖于全局状态的改变,这种写法确实不应该提倡。
https://godbolt.org/z/MW7crn7xY 这个是可供测试的代码
这里有一个更简单的复现代码,用于测试类型完整性的,事实上和该类型第一次实例化的位置有关,和定义的位置关系不大。
https://godbolt.org/z/dGqsaxG8z
代码不应该依赖这些可以观测到的全局状态改变,否则容易造成 ODR 违背
明白了,就是说在concept实例化后就不应该修改,会造成concept判断不一致的状态,是吗?
我自己在写程序的时候发现,concept的判断时间是在定义处,而不是在使用处,换言之,如果先定义了一个concept,之后写了一些代码,影响了concept判定条件,即使在之后使用这个concept,依然会按照修改之前的结果判定,这个是正常的吗。如果是正常的,是否应该强调一下?