为具有 returns 约束值的成员函数的对象指定概念
Specifying a concept for an object with a member function that returns a constrained value
我试图通过移植我的一些旧代码来围绕 C++ 20 的概念和约束。
struct Status
{
std::string status;
std::time_t statusDate;
};
struct CurrentStatusStack
{
std::vector<Status> statusVec;
std::vector<std::filesystem::path> ticketPathVec;
};
void setBar(CurrentStatusStack s)
{
ui->setLatestStatusMessage(s.statusVec.back().status);
ui->setLatestStatusMessagePath(s.ticketPathVec.back());
}
为了将上述代码块转换为类似但通用的函数 setFoo(const T& t)
并确保 T
类型实现 setBar
要求的函数,我写了一些概念:
- 一个
ContainerOf
概念
/*
`ContainerOf` requires container (could be a vector or a set
or other STL-like containers) to implement at least:
1. `cbegin()` that returns a const iterator pointer to the first element.
2. `empty()` an emptiness check fn.
*/
template <class Container, typename T>
concept ContainerOf = requires(Container a, T)
{
requires std::regular<Container>;
requires std::same_as<typename Container::value_type, T>;
{
a.cbegin()
} -> std::same_as<typename Container::const_iterator>;
{
a.empty()
} -> std::same_as<bool>;
};
- 一个
HasTicketPaths
概念
/*
`HasTicketPaths` ensures that that structure given implements a `getTicketPaths`
function that returns a container that satisfies `ContainerOf` with
`std::filesystem::path` elements in it.
*/
template <typename T>
concept HasTicketPaths = requires(T t)
{
{
t.getTicketPaths()
} -> ContainerOf<fs::path>;
};
- 一个
IsStatus
概念
/*
To set status the obj needs at least two elements:
1. Status string and
2. the date the status was posted,
`IsStatus` ensure those constrients by requiring `status` and
`statusDate` functions that return a `std::string` and `std::time_t`
respectively.
*/
template <typename T>
concept IsStatus = requires(T t)
{
{
t.status()
} -> std::same_as<std::string>;
{
t.statusDate()
} -> std::same_as<std::time_t>;
};
现在我认为所有要做的就是以某种方式将这两个概念结合到 HasStatus
概念中,并将函数原型更改为
template <typename T>
requires HasStatus<T> && requires HasTicketPaths<T>
void setFoo(const T& t);
但我不知道该怎么做。
我想象它看起来像这样
/*
`HasStatus` ensures that the container has a `getStatus` function that return
a container with each element type ensuring `IsStatus`'s requirement.
*/
template <typename T>
concept HasStatus = requires(T t)
{
{
t.getStatus()
} -> ContainerOf<IsStatus>;
};
但它会产生以下错误
invalid use of ‘decltype(auto) [requires ::IsStatus<<placeholder>, >]’ in template argument
70 | } -> ContainerOf<IsStatus>;
我想我误解了 concepts
的实际工作原理,但我不确定要寻找 where/what。
概念不是 类型,因此它不能作为容器元素类型出现——也不能出现在对象类型中(这就是为什么你必须使用 std::vector<std::any>
来近似 std::vector<std::copyable>
) 也不是你的概念的类型 ContainerOf
。此外,您不能将概念用作 模板参数 ,因此您不能拥有更高阶的 ContainerLike
概念。
你可以做的是创建一个只检查 empty
的 Container
概念,添加约束
{ *c.cbegin() } -> IsStatus;
并将其应用到另一个概念中的t.getStatus()
。
为了帮助可能偶然发现这个问题的其他人(或未来的我),下面是一个最小的 complete/reproducible 示例,说明我最终实现该问题的方式
#include <concepts>
#include <ctime>
#include <iostream>
#include <string>
#include <vector>
template <typename T>
concept IsStatus = requires(T t) {
{ t.getStatus() } -> std::same_as<const std::string&>;
{ t.getStatusDate() } -> std::same_as<const std::time_t&>;
};
template <class Container>
concept ContainerOfStatus = requires(Container c) {
{ c.empty() } -> std::same_as<bool>;
{ *c.cbegin() } -> IsStatus;
};
template <typename T>
concept HasStatus = requires(T t) {
{ t.getAllStatus() } -> ContainerOfStatus;
};
struct Status {
std::string status;
std::time_t statusDate;
const std::string& getStatus() const { return status; };
const std::time_t& getStatusDate() const { return statusDate; };
};
struct CurrentStatusStack {
std::vector<Status> statusVec;
const std::vector<Status>& getAllStatus() const { return statusVec; };
};
template <typename T>
requires HasStatus<T>
void printStatus(T t) {
std::cout << t.getAllStatus().cbegin()->getStatus() << std::endl;
}
int main() {
Status s{"some status", std::time_t(nullptr)};
CurrentStatusStack st;
st.statusVec.push_back(s);
std::cout << st.getAllStatus().cbegin()->getStatus() << std::endl;
printStatus(st);
}
这是另一个非常
我试图通过移植我的一些旧代码来围绕 C++ 20 的概念和约束。
struct Status
{
std::string status;
std::time_t statusDate;
};
struct CurrentStatusStack
{
std::vector<Status> statusVec;
std::vector<std::filesystem::path> ticketPathVec;
};
void setBar(CurrentStatusStack s)
{
ui->setLatestStatusMessage(s.statusVec.back().status);
ui->setLatestStatusMessagePath(s.ticketPathVec.back());
}
为了将上述代码块转换为类似但通用的函数 setFoo(const T& t)
并确保 T
类型实现 setBar
要求的函数,我写了一些概念:
- 一个
ContainerOf
概念
/*
`ContainerOf` requires container (could be a vector or a set
or other STL-like containers) to implement at least:
1. `cbegin()` that returns a const iterator pointer to the first element.
2. `empty()` an emptiness check fn.
*/
template <class Container, typename T>
concept ContainerOf = requires(Container a, T)
{
requires std::regular<Container>;
requires std::same_as<typename Container::value_type, T>;
{
a.cbegin()
} -> std::same_as<typename Container::const_iterator>;
{
a.empty()
} -> std::same_as<bool>;
};
- 一个
HasTicketPaths
概念
/*
`HasTicketPaths` ensures that that structure given implements a `getTicketPaths`
function that returns a container that satisfies `ContainerOf` with
`std::filesystem::path` elements in it.
*/
template <typename T>
concept HasTicketPaths = requires(T t)
{
{
t.getTicketPaths()
} -> ContainerOf<fs::path>;
};
- 一个
IsStatus
概念
/*
To set status the obj needs at least two elements:
1. Status string and
2. the date the status was posted,
`IsStatus` ensure those constrients by requiring `status` and
`statusDate` functions that return a `std::string` and `std::time_t`
respectively.
*/
template <typename T>
concept IsStatus = requires(T t)
{
{
t.status()
} -> std::same_as<std::string>;
{
t.statusDate()
} -> std::same_as<std::time_t>;
};
现在我认为所有要做的就是以某种方式将这两个概念结合到 HasStatus
概念中,并将函数原型更改为
template <typename T>
requires HasStatus<T> && requires HasTicketPaths<T>
void setFoo(const T& t);
但我不知道该怎么做。
我想象它看起来像这样
/*
`HasStatus` ensures that the container has a `getStatus` function that return
a container with each element type ensuring `IsStatus`'s requirement.
*/
template <typename T>
concept HasStatus = requires(T t)
{
{
t.getStatus()
} -> ContainerOf<IsStatus>;
};
但它会产生以下错误
invalid use of ‘decltype(auto) [requires ::IsStatus<<placeholder>, >]’ in template argument
70 | } -> ContainerOf<IsStatus>;
我想我误解了 concepts
的实际工作原理,但我不确定要寻找 where/what。
概念不是 类型,因此它不能作为容器元素类型出现——也不能出现在对象类型中(这就是为什么你必须使用 std::vector<std::any>
来近似 std::vector<std::copyable>
) 也不是你的概念的类型 ContainerOf
。此外,您不能将概念用作 模板参数 ,因此您不能拥有更高阶的 ContainerLike
概念。
你可以做的是创建一个只检查 empty
的 Container
概念,添加约束
{ *c.cbegin() } -> IsStatus;
并将其应用到另一个概念中的t.getStatus()
。
为了帮助可能偶然发现这个问题的其他人(或未来的我),下面是一个最小的 complete/reproducible 示例,说明我最终实现该问题的方式
#include <concepts>
#include <ctime>
#include <iostream>
#include <string>
#include <vector>
template <typename T>
concept IsStatus = requires(T t) {
{ t.getStatus() } -> std::same_as<const std::string&>;
{ t.getStatusDate() } -> std::same_as<const std::time_t&>;
};
template <class Container>
concept ContainerOfStatus = requires(Container c) {
{ c.empty() } -> std::same_as<bool>;
{ *c.cbegin() } -> IsStatus;
};
template <typename T>
concept HasStatus = requires(T t) {
{ t.getAllStatus() } -> ContainerOfStatus;
};
struct Status {
std::string status;
std::time_t statusDate;
const std::string& getStatus() const { return status; };
const std::time_t& getStatusDate() const { return statusDate; };
};
struct CurrentStatusStack {
std::vector<Status> statusVec;
const std::vector<Status>& getAllStatus() const { return statusVec; };
};
template <typename T>
requires HasStatus<T>
void printStatus(T t) {
std::cout << t.getAllStatus().cbegin()->getStatus() << std::endl;
}
int main() {
Status s{"some status", std::time_t(nullptr)};
CurrentStatusStack st;
st.statusVec.push_back(s);
std::cout << st.getAllStatus().cbegin()->getStatus() << std::endl;
printStatus(st);
}
这是另一个非常