假设我有一个deserialize
函数:
template <typename T>
T deserialize(const std::string& src);
// Specialized for various types
// ...
,并希望为deserialize
专门化的类型定义Deserializable
概念。以下版本有什么不同吗?
template <typename T>
concept Deserializable = requires(std::string s) { deserialize<T>(s); };
// concept Deserializable = requires(std::string& s) { deserialize<T>(s); };
// concept Deserializable = requires(const std::string s) { deserialize<T>(s); };
// concept Deserializable = requires(const std::string& s) { deserialize<T>(s); };
如果requires
类似于正常函数,那么我期望第1 (resp)。第3个版本与第2个版本相同。4)版本,因为普通函数体中的名称s
是左值。但是,我看到标准库使用引用类型作为requires
参数,例如:
template< class T >
concept range = requires(T& t) {
ranges::begin(t); // equality-preserving for forward iterators
ranges::end (t);
};
,这似乎暗示了引用与值的关系。
更一般地说,cv限定符和requires
参数的引用重要吗?
更新:我提出了一个测试,以表明requires
确实似乎表现得像正常的函数:
template <typename T>
void f(T&&, T&&) {}
template <typename T>
concept Foo = requires(int x, int& y, int&& z) {
f(x, y);
f(x, z);
f(x, 123); // won't compile: deduced int& and int
};
int main()
{
}
所以看起来上面标准库示例中的requires(T& t)
与requires(T t)
没有什么不同。总是这样吗?
如果T
是右值引用类型U&&
,T&
是U&
,但只有当使用decltype
或类似std::forward
时才有关系。唯一的另一个形式上的区别是,它阻止了参数被调整如果是数组或函数类型,则为指针,这也很少有关系。
它也可能意味着避免暗示一个类型是可复制/可移动的(通常需要按值函数参数)。