C ++ TS Концепции и средства доступа

Я хотел использовать Concepts TS, чтобы помочь мне с ограничением данных. Я буду говорить о концепциях, обсуждаемых в p0121r0 и я использую GCC 6.2 для тестов.

Возьмите этот простой кусок кода:

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

Я должен передать в struct Tester тип с тестовое задание свойство, которое можно увеличивать и уменьшать. Хорошо.

struct A
{
unsigned test;
}

Tester<A> a;

Работает как положено. Очевидно, что следующий не будет работать:

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

Теперь реальный вопрос: почему следующий не работает?

class D
{
unsigned test;
};

Tester<D> d; // error: private???

Я попытался покопаться в статье std, но я не могу понять, что такое поведение ожидается, если в самом std отсутствует эта возможность, если компилятор работает неправильно …

Или, может быть, мне нужно объявить о дружбе, но какой в ​​этом смысл? Это ситуация, в которой ограничения концепций не должны быть ограничен по доступу …

Есть идеи о том, что здесь происходит?

РЕДАКТИРОВАТЬ:
Не всегда легко дать представление о проблеме на простом примере. Это немного сложнее, но больше похоже на реальный случай:

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

Как видите, очевидно, что счетчик, нагрузка а также разгружать должны быть частными / защищенными, и к ним нужно обращаться только из Scoper.
Если я использую абстрактный базовый класс, я могу только ограничить счетчик а также разгружать, но нет нагрузка (для которого, как вы можете видеть, я не знаю, как обрабатывать правильный синтаксис …).

Возможно, это не изменит ваши ответы, но проблема, возможно, немного чище.

5

Решение

Эта концепция:

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

требует, чтобы T иметь общедоступный член test это как постинкрементный, так и постдекремблируемый.

Этот тип:

class D
{
unsigned test;
};

не имеет общедоступного членского теста. В конце концов, я не могу написать ни одно из этих утверждений:

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

Следовательно, D не соответствует концепции test_is_available, test очень много не доступно.

Если ты хочешь D быть test_is_availableвам нужно будет сделать test public, Вы не можете просто friend что-то, что просто нарушает концептуальную систему — вы получите D это test_is_available для некоторых типов, но не для других. Это не совсем то, как все должно работать.

9

Другие решения

Других решений пока нет …