使用 C++ 20 概念检查函数 returns 是否为 const 值

Using c++ 20 Concept to check if a function returns a const value

我正在尝试使用概念来检测给定类型的开始函数 returns 是“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”集合持有类型的版本。如何正确检测到容器包含常量值?

这里的直接问题是 decltype((*t.begin())) for std::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(不是int&,不是int const&,只是int)。这是 not 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> 不是 RangeOfConstset<int>vector<int> constiota_view<int>

但是...它还会说 vector<bool>RangeOfConst,即使您 可以 修改它们!我会把那个留给以后思考。

直接的方法是,如果T是const,那么T应该和add_const_t<T>是同一类型,所以你只需要改变你的IsConst

template <typename T>
concept IsConst = std::is_same_v<T, std::add_const_t<T>>;