我想使用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;
};
我必须将带有 test 属性的类型传递给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 访问。 如果我使用抽象基类,我只能约束计数器和卸载,但不能加载(正如你所看到的那样,我做了不知道如何处理正确的语法......)。
也许这不会改变你的答案,但问题可能有点清晰。
答案 0 :(得分:9)
这个概念:
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
但不会其他。事实并非如此。