C ++ TS Concepts and Accessors

I wanted to use the TS concept to help me with data restriction. I will talk about the concepts discussed in p0121r0, and I use GCC 6.2 for tests.

Take this simple snippet of code:

template<typename T> concept bool test_is_available = requires(T t) { t.test; { t.test++ }; { t.test-- }; }; template<test_is_available T> struct Tester { T t; }; 

I need to pass a test tester with the test property to the test, which is incremental and decrementing. Good.

 struct A { unsigned test; } Tester<A> a; 

It works as expected. Obviously, the following will not work:

 struct B { std::string test; }; struct C { unsigned not_test; }; Tester<B> b; // error: test++ and test-- are ill formed Tester<C> c; // error: no test available 

Now, the real question is: why does the following not work?

 class D { unsigned test; }; Tester<D> d; // error: private??? 

I tried to look into the std document, but I canโ€™t understand that this behavior is expected if std itself does not have this capability, if the compiler does not work correctly ...

Or maybe I need to declare some kind of friendship, but what's the point? This is a situation in which the limitations of concepts should not be limited to accessories ...

Any ideas on what's going on here?

EDIT: It's not easy to give an idea of โ€‹โ€‹the problem with a simple example. This is a bit more complicated, but more like a real case:

 #include <cassert> #include <utility> template<typename T> concept bool Countable = requires(T t) { t.counter; { ++t.counter }; { --t.counter }; //{ t.load(auto&&...) } -> void; <-- I am not sure how to handle this { t.unload() } -> void; }; template<Countable T> class Scoper { public: template<typename... Args> Scoper(T& t, Args... args) : m_t(&t) { ++t.counter; t.load(std::forward<Args>(args)...); } ~Scoper() { --m_t->counter; m_t->unload(); } private: T* m_t; }; class Scopeable { public: unsigned getCounter() const { return counter; } //private: //template<Countable> friend class Scoper; <-- does not work void load(char, int) {} void unload() {} unsigned counter = 0; }; int main() { Scopeable scopeable; assert(scopeable.getCounter() == 0); { Scoper<Scopeable> scoper(scopeable, 'A', 2); assert(scopeable.getCounter() == 1); } assert(scopeable.getCounter() == 0); } 

As you can see, it is obvious that the counter, loading and unloading should be confidential / secure and that they should be accessed only from Scoper. If I use an abstract base class, I can restrict the counter and unload, but not load (for which, as you can see, I donโ€™t know how to handle the correct syntax ...).

This may not change your answers, but the problem is probably a little cleaner.

+5
source share
1 answer

This concept:

 template<typename T> concept bool test_is_available = requires(T t) { t.test; { t.test++ }; { t.test-- }; }; 

requires that T have a public test element that is both post-incremental and post-decrement.

This type:

 class D { unsigned test; }; 

does not have a public member test. In the end, I cannot write any of these statements:

 D d; d.test; // error d.test++; // error d.test--; // error 

Therefore, D does not correspond to the concept of test_is_available . test very unavailable.

If you want D be test_is_available , you need to do test public . You can't just friend something that just violates the conceptual system - you get D that test_is_available for some types, but not for others. This is not how things should work.

+9
source

Source: https://habr.com/ru/post/1257527/


All Articles