使用c++20Concept检查函数是否返回const值
我正在尝试使用概念来检测给定类型的开始函数是否将迭代器返回到“const T&”或仅返回到“T&”。但我不确定如何最好地去做,我尝试了以下方法:
#include <iostream>
#include <concepts>
#include <vector>
#include <set>
template <typename T>
concept IsConst = std::is_const<T>::value;
template<typename T>
concept IsIterableOfConst = requires (T& t) { { *t.begin() } -> IsConst; };
template <IsIterableOfConst T>
void test()
{
std::cout << "Yes" << std::endl;
}
template <typename T>
void test()
{
std::cout << "No" << std::endl;
}
int main(int argc, char** argv)
{
test<std::set<int>>();
test<std::vector<int>>();
}
这会产生输出“No No”,当我希望它产生输出“Yes No”时,因为 std::set 中的迭代器应该,据我所知,总是迭代持有类型的集合的“const”版本. 如何正确检测容器包含 const 值?
回答
这里的直接问题是decltype((*t.begin()))forstd::set<int>给你类型int const&,类型特征std::is_const<T>检查是否T是某种类型U const。引用不是常量。
您需要先剥离参考:
template <typename T>
concept IsConst = std::is_const_v<std::remove_reference_t<T>>;
也就是说,这并不是对常量性的完全正确检查。考虑根据views::iota(0, 10)需要为您提供一堆整数的范围。这个范围的引用类型是int(not int&, not int const&, just int)。这不是一种const类型,因此您的概念会说这样的范围不能建模IsIterableOfConst(旁注:术语是范围,而不是可迭代的)。但是这样的范围确实是 const - 你不能修改它的内容。
所以更接近的答案是:
template <typename T>
inline constexpr bool is_suitably_const = true;
template <typename T>
inline constexpr bool is_suitably_const<T&> = is_const_v<T>;
template <typename R>
concept RangeOfConst = range<R> && is_suitably_const<range_reference_t<R>>;
这会说这vector<int>不是 a RangeOfConst,set<int>并且vector<int> const是iota_view<int>。
但是...它也可以说vector<bool>是 a RangeOfConst,即使您可以修改它们!我会把那件事留作未来思考的事情。