Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
808 views
in Technique[技术] by (71.8m points)

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

I'm trying to use concepts in order to be able to detect if a given type's begin function returns an iterator to "const T&" or just to "T&". But I'm not sure how one would best go about it, I have tried the following:

#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>>();
}

This produces the output "No No" when I would expect it to produce the output "Yes No" as iterators in std::set should, as far as I'm aware, always iterate over "const" versions of the sets held type. How do I correctly detect that the container contains const values?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The direct issue here is that decltype((*t.begin())) for std::set<int> gives you the type int const&, and the type trait std::is_const<T> checks if T is some type U const. A reference is not const.

You need to strip the reference first:

template <typename T>
concept IsConst = std::is_const_v<std::remove_reference_t<T>>;

That said, this isn't really a completely correct check for const-ness. Consider the range views::iota(0, 10) which gives you a bunch of integers on demand. The reference type of this range is int (not int&, not int const&, just int). This is not a const type, so your concept would say that such a range does not model IsIterableOfConst (side-note: the term is range, not iterable). But such a range really is const - you cannot modify the contents of it.

So a closer answer would be:

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>>;

This would say that vector<int> is not a RangeOfConst, set<int> and vector<int> const are, as is iota_view<int>.

But... it would also say that vector<bool> is a RangeOfConst, even though you can modify those! I'll leave that one as something to ponder for the future.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...