#include <mutex>
#include <shared_mutex>
template<typename T>
concept is_buffer = requires (T t) {
{ t.pointer() } -> std::same_as<char*>;
{ t.capacity() } -> std::same_as<size_t>;
{ t.rwlock() } -> std::same_as<std::shared_mutex&>;
};
template<typename Buffer>
requires is_buffer<Buffer>
class buffer_stream {
};
class shared_array_buffer {
private:
struct meta {
char* ptr {};
size_t capacity {};
std::mutex mutex {};
std::shared_mutex rwlock{};
int reference_count {};
};
meta* meta_ {};
/* Error occured here */
friend class buffer_stream<shared_array_buffer>;
public:
char* pointer() {
return meta_->ptr;
}
size_t capacity() {
return meta_->capacity;
}
std::shared_mutex& rwlock() {
return meta_->rwlock;
}
};
int main() {
shared_array_buffer buffer;
buffer_stream<shared_array_buffer> stream;
}
在这段代码中,我使用类
buffer_stream
作为shared_array_buffer
和unique_array_buffer
的友元类,它们都是有概念的模板类。
编译器说
template constraint failure for ‘template<class Buffer> requires is_buffer<Buffer> class buffer_stream’
,因为‘t’ has incomplete type
(在类shared_array_buffer中)。
我想知道为什么
shared_array_buffer
是一个不完整的类型。成员的所有类型都是完全定义的。
friend class buffer_stream<shared_array_buffer>;
这使得
is_buffer
concept
检查 shared_array_buffer
是否有效,但 shared_array_buffer
不完整于 friend
声明的点,因此编译失败。
解决方法可能是使用
static_assert
来延迟验证:
template <typename Buffer>
class buffer_stream {
static_assert(is_buffer<Buffer>);
};
另一种选择是让
buffer_stream
继承缓冲区类型。然后,您可以让它具有 protected
访问器等,而不需要将其设为 friend
:
class shared_array_buffer {
private:
struct meta {
char* ptr{};
size_t capacity{};
std::mutex mutex{};
std::shared_mutex rwlock{};
int reference_count{};
};
meta* meta_{};
public:
char* pointer() { return meta_->ptr; }
size_t capacity() { return meta_->capacity; }
std::shared_mutex& rwlock() { return meta_->rwlock; }
};
template <typename Buffer>
requires is_buffer<Buffer>
class buffer_stream : public Buffer {
};
我想这与实例化模板的顺序以及评估
requires
子句的时间有关。删除 require 子句并将其替换为 static_cast
似乎是一种解决方法:
template<typename Buffer>
// requires is_buffer<Buffer> <--- this fails
class buffer_stream {
static_assert(is_buffer<Buffer>); // <--- this succeeds
};
这对于所有主要编译器的行为都是相同的请参阅演示。