使用具有循环依赖性的 ADL 的 C++20 概念
C++20 concepts using ADL with circular dependency
我对使用 ADL 的概念有疑问。
编辑 1:我提到 ADL,因为 parse
函数应该用用户定义的类型重载。
from_string_view_parsable
概念没有看到下面的 parse
函数,因为 ADL 不适用于它们。
函数需要在概念定义之前定义或前向声明,但是第二次重载存在循环依赖,因此无法完成。
https://godbolt.org/z/frn1jKv5E
#include <sstream>
#include <optional>
template <typename T>
concept from_string_view_parsable = requires(std::string_view sv, T& x) {
{ parse(sv, x) };
};
void parse(std::string_view input, int& out)
{
auto ss = std::stringstream{};
ss << input;
ss >> out;
}
template <from_string_view_parsable T>
requires std::default_initializable<T>
void parse(std::string_view input, std::optional<T>& out)
{
out = T{};
parse(input, *out);
}
template <from_string_view_parsable T>
void use_parse(T& t) {
parse("123", t);
}
int main() {
std::optional<int> x;
use_parse(x);
}
我尝试做的事情是根本错误的,还是有任何解决方法可以让我这样做?
您可以将 requires
表达式推迟到类型特征,它可以被前向声明:
#include <sstream>
#include <optional>
#include <string_view>
#include <type_traits>
template <typename T>
struct is_from_string_view_parsable;
template <typename T>
concept from_string_view_parsable = is_from_string_view_parsable<T>::value;
void parse(std::string_view input, int& out)
{
auto ss = std::stringstream{};
ss << input;
ss >> out;
}
template <from_string_view_parsable T>
requires std::default_initializable<T>
void parse(std::string_view input, std::optional<T>& out)
{
out = T{};
parse(input, *out);
}
template <from_string_view_parsable T>
void use_parse(T& t) {
parse("123", t);
}
template <typename T>
struct is_from_string_view_parsable : std::bool_constant<
requires(std::string_view sv, T& x) {
{ parse(sv, x) };
}
> {};
int main() {
std::optional<int> x;
use_parse(x);
}
现在,我不确定这是否违反了任何规则,但我认为不应该。请注意,约束的评估不会在程序的不同点发生变化。
由于无法向前声明概念,因此 from_string_view_parsable
的定义必须出现在 std::optional
重载之后。
相反,您可以使用 requires 子句(或 static_assert
)来约束 parse(intput, *out)
必须格式正确,如下所示:
#include <sstream>
#include <optional>
void parse(std::string_view input, int& out)
{
auto ss = std::stringstream{};
ss << input;
ss >> out;
}
template <std::default_initializable T>
void parse(std::string_view input, std::optional<T>& out)
requires requires { parse(input, *out); }
{
out = T{};
parse(input, *out);
}
template <typename T>
concept from_string_view_parsable = requires(std::string_view sv, T& x) {
{ parse(sv, x) };
};
template <from_string_view_parsable T>
void use_parse(T& t) {
parse("123", t);
}
int main() {
std::optional<int> x;
use_parse(x);
}
我对使用 ADL 的概念有疑问。
编辑 1:我提到 ADL,因为 parse
函数应该用用户定义的类型重载。
from_string_view_parsable
概念没有看到下面的 parse
函数,因为 ADL 不适用于它们。
函数需要在概念定义之前定义或前向声明,但是第二次重载存在循环依赖,因此无法完成。
https://godbolt.org/z/frn1jKv5E
#include <sstream>
#include <optional>
template <typename T>
concept from_string_view_parsable = requires(std::string_view sv, T& x) {
{ parse(sv, x) };
};
void parse(std::string_view input, int& out)
{
auto ss = std::stringstream{};
ss << input;
ss >> out;
}
template <from_string_view_parsable T>
requires std::default_initializable<T>
void parse(std::string_view input, std::optional<T>& out)
{
out = T{};
parse(input, *out);
}
template <from_string_view_parsable T>
void use_parse(T& t) {
parse("123", t);
}
int main() {
std::optional<int> x;
use_parse(x);
}
我尝试做的事情是根本错误的,还是有任何解决方法可以让我这样做?
您可以将 requires
表达式推迟到类型特征,它可以被前向声明:
#include <sstream>
#include <optional>
#include <string_view>
#include <type_traits>
template <typename T>
struct is_from_string_view_parsable;
template <typename T>
concept from_string_view_parsable = is_from_string_view_parsable<T>::value;
void parse(std::string_view input, int& out)
{
auto ss = std::stringstream{};
ss << input;
ss >> out;
}
template <from_string_view_parsable T>
requires std::default_initializable<T>
void parse(std::string_view input, std::optional<T>& out)
{
out = T{};
parse(input, *out);
}
template <from_string_view_parsable T>
void use_parse(T& t) {
parse("123", t);
}
template <typename T>
struct is_from_string_view_parsable : std::bool_constant<
requires(std::string_view sv, T& x) {
{ parse(sv, x) };
}
> {};
int main() {
std::optional<int> x;
use_parse(x);
}
现在,我不确定这是否违反了任何规则,但我认为不应该。请注意,约束的评估不会在程序的不同点发生变化。
由于无法向前声明概念,因此 from_string_view_parsable
的定义必须出现在 std::optional
重载之后。
相反,您可以使用 requires 子句(或 static_assert
)来约束 parse(intput, *out)
必须格式正确,如下所示:
#include <sstream>
#include <optional>
void parse(std::string_view input, int& out)
{
auto ss = std::stringstream{};
ss << input;
ss >> out;
}
template <std::default_initializable T>
void parse(std::string_view input, std::optional<T>& out)
requires requires { parse(input, *out); }
{
out = T{};
parse(input, *out);
}
template <typename T>
concept from_string_view_parsable = requires(std::string_view sv, T& x) {
{ parse(sv, x) };
};
template <from_string_view_parsable T>
void use_parse(T& t) {
parse("123", t);
}
int main() {
std::optional<int> x;
use_parse(x);
}