需要定义模板成员函数的概念定义 [英] Concept definition requiring a constrained template member function
问题描述
注意:后面的所有内容均使用GCC 6.1中的Concepts TS实现
假设我有一个概念 Surface
,如下所示:
Let's say I have a concept Surface
, like the following:
template <typename T>
concept bool Surface() {
return requires(T& t, point2f p, float radius) {
{ t.move_to(p) };
{ t.line_to(p) };
{ t.arc(p, radius) };
// etc...
};
}
现在我想定义另一个概念, Drawable
,它将任何类型与成员函数匹配:
Now I want to define another concept, Drawable
, which matches any type with a member function:
template <typename S>
requires Surface<S>()
void draw(S& surface) const;
ie
struct triangle {
void draw(Surface& surface) const;
};
static_assert(Drawable<triangle>(), ""); // Should pass
即 Drawable
是具有模板化const成员函数 draw()
的事物,它对满足 Surface
要求的事物进行左值引用。用语言可以很容易地指定它,但是我还不太清楚如何用Concepts TS在C ++中做到这一点。 显而易见的语法无效:
That is, a Drawable
is something which has a templated const member function draw()
taking an lvalue reference to something which satisfies the Surface
requirements. This is reasonably easy to specify in words, but I can't quite work out how to do it in C++ with the Concepts TS. The "obvious" syntax doesn't work:
template <typename T>
concept bool Drawable() {
return requires(const T& t, Surface& surface) {
{ t.draw(surface) } -> void;
};
}
错误:不允许使用'auto'参数此上下文
error: 'auto' parameter not permitted in this context
添加第二个模板参数可以编译概念定义,但是:
Adding a second template parameter allows the concept definition to compile, but:
template <typename T, Surface S>
concept bool Drawable() {
return requires(const T& t, S& s) {
{ t.draw(s) };
};
}
static_assert(Drawable<triangle>(), "");
模板参数推导/替换失败:
无法推导模板参数'S'
template argument deduction/substitution failed: couldn't deduce template parameter 'S'
现在我们只能检查是否特定的< Drawable
,表面
> 对与 Drawable
概念匹配,这并不完全对。 (类型 D
要么具有必需的成员函数,要么不具有:这不取决于哪个特定的 Surface
我们检查一下。)
now we can only check whether a particular <Drawable
, Surface
> pair matches the Drawable
concept, which isn't quite right. (A type D
either has the required member function or it does not: that doesn't depend on which particular Surface
we check.)
我敢肯定,我可以做我想做的事,但是我无法弄清楚语法,而且例子太多了上线了。有人知道如何编写一个要求类型具有约束模板成员函数的概念定义吗?
I'm sure it's possible to do what I'm after, but I can't work out the syntax and there aren't too many examples online yet. Does anybody know how to write a concept definition which requires type to have a constrained template member function?
推荐答案
您在寻找什么for为编译器合成 Surface
的原型提供了一种方法。也就是说,某些私有的匿名类型至少满足了 Surface
的概念。尽可能少。目前,Concepts TS不支持自动合成原型的机制,因此我们只能手动进行。这是一个复杂的过程 ,因为可以很容易地找到具有该概念指定的更多功能的原型候选者。
What you're looking for is for a way for the compiler to synthesize an archetype of Surface
. That is, some private, anonymous type that minimally satisfies the Surface
concept. As minimally as possible. Concepts TS doesn't currently allow for a mechanism for automatically synthesizing archetypes, so we're left with doing it manually. It's quite a complicated process, since it's very easy to come up with archetype candidates that have way more functionality that the concept specifies.
在这种情况下,我们可以提出类似这样的东西:
In this case, we can come up with something like:
namespace archetypes {
// don't use this in real code!
struct SurfaceModel {
// none of the special members
SurfaceModel() = delete;
SurfaceModel(SurfaceModel const& ) = delete;
SurfaceModel(SurfaceModel&& ) = delete;
~SurfaceModel() = delete;
void operator=(SurfaceModel const& ) = delete;
void operator=(SurfaceModel&& ) = delete;
// here's the actual concept
void move_to(point2f );
void line_to(point2f );
void arc(point2f, float);
// etc.
};
static_assert(Surface<SurfaceModel>());
}
然后:
template <typename T>
concept bool Drawable() {
return requires(const T& t, archetypes::SurfaceModel& surface) {
{ t.draw(surface) } -> void;
};
}
这些是有效的概念,可能有用。请注意, SurfaceModel
原型还有很大的改进空间。我有一个特定的函数 void move_to(point2f)
,但是这个概念只要求它可以用一个 point2f
。不需要 move_to()
和 line_to()
都接受类型为 point2f的参数
,它们都可以完成完全不同的事情:
These are valid concepts, that probably work. Note that there's a lot of room for even more refinement on the SurfaceModel
archetype. I have a specific function void move_to(point2f )
, but the concept just requires that it's callable with an lvalue of type point2f
. There's no requirement that move_to()
and line_to()
both take an argument of type point2f
, they could both take complete different things:
struct SurfaceModel {
// ...
struct X { X(point2f ); };
struct Y { Y(point2f ); };
void move_to(X );
void line_to(Y );
// ...
};
这种偏执症使原型更好,并说明了这个问题的复杂程度。
This kind of paranoia makes for a better archetype, and serves to illustrate how complex this problem could be.
这篇关于需要定义模板成员函数的概念定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!