如何使用 C++20 概念根据函数的 return 类型做不同的事情?
How to use C++20 concepts to do different things based on return type of a function?
我想制作一个通用的 print(x)
函数,它对不同的类型有不同的行为。
到目前为止,我所拥有的适用于所有容器类型,包括我自己编写的容器类型。但是,要么调用了“错误的”函数,要么由于歧义而无法编译。
这是我的代码:
#include <iostream>
#include <concepts>
class Container
{
int x, y, z;
public:
Container(int a, int b, int c) : x(a), y(b), z(c) {}
Container() : x(0), y(0), z(0) {}
std::size_t size() const { return 3; }
const int& operator[] (std::size_t index) const { if(index == 0) return x; else if(index == 1) return y; else return z; }
int& operator[] (std::size_t index) { if(index == 0) return x; else if(index == 1) return y; else return z; }
};
template<typename T>
concept printable_num = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::same_as<int&>;
};
template<printable_num T>
void print(const T& t) {
std::size_t i = 0;
for(;i < t.size() - 1; i++)
std::cout << t[i] << ", ";
std::cout << t[i] << std::endl;
}
template<typename T>
concept printable = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::convertible_to<char>;
};
template<printable T>
void print(const T& t) {
std::size_t i = 0;
for(;i < t.size() - 1; i++)
std::cout << t[i];
std::cout << t[i] << std::endl;
}
int main()
{
Container c{1, 2, 3};
print(c);
Container empty;
print(empty);
std::string s{"this is some string"};
print(s);
return 0;
}
如您所见,如果从 operator[]
返回的类型是 int&
,我想打印一个分隔符。由于歧义,这不会编译。
有没有办法进行编译并让我到达我想要的位置(为 std::string 调用不带分隔符的打印函数,为我自己的容器类型调用带分隔符的打印函数)?
给定一个整数(或左值到 1),您是否同意它可以转换为 char
?约束会准确检查您让它们检查您问题中的类型。
一种解决方法是 constraint subsumption。这意味着(以一种非常手波浪的方式)如果你的概念被写成相同基本约束的结合(或析取),编译器可以规范化表达式以选择“更专业的”。将其应用于您的示例..
template<typename T>
concept printable = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::convertible_to<char>;
};
template<typename T>
concept printable_num = printable<T> && requires (T t, std::size_t s)
{
{ t[s] } -> std::same_as<int&>;
};
请注意我们如何使用 printable
将 printable_num
定义为“更具体”的概念。 运行这个例子,我们得到了output you are after.
我想制作一个通用的 print(x)
函数,它对不同的类型有不同的行为。
到目前为止,我所拥有的适用于所有容器类型,包括我自己编写的容器类型。但是,要么调用了“错误的”函数,要么由于歧义而无法编译。
这是我的代码:
#include <iostream>
#include <concepts>
class Container
{
int x, y, z;
public:
Container(int a, int b, int c) : x(a), y(b), z(c) {}
Container() : x(0), y(0), z(0) {}
std::size_t size() const { return 3; }
const int& operator[] (std::size_t index) const { if(index == 0) return x; else if(index == 1) return y; else return z; }
int& operator[] (std::size_t index) { if(index == 0) return x; else if(index == 1) return y; else return z; }
};
template<typename T>
concept printable_num = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::same_as<int&>;
};
template<printable_num T>
void print(const T& t) {
std::size_t i = 0;
for(;i < t.size() - 1; i++)
std::cout << t[i] << ", ";
std::cout << t[i] << std::endl;
}
template<typename T>
concept printable = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::convertible_to<char>;
};
template<printable T>
void print(const T& t) {
std::size_t i = 0;
for(;i < t.size() - 1; i++)
std::cout << t[i];
std::cout << t[i] << std::endl;
}
int main()
{
Container c{1, 2, 3};
print(c);
Container empty;
print(empty);
std::string s{"this is some string"};
print(s);
return 0;
}
如您所见,如果从 operator[]
返回的类型是 int&
,我想打印一个分隔符。由于歧义,这不会编译。
有没有办法进行编译并让我到达我想要的位置(为 std::string 调用不带分隔符的打印函数,为我自己的容器类型调用带分隔符的打印函数)?
给定一个整数(或左值到 1),您是否同意它可以转换为 char
?约束会准确检查您让它们检查您问题中的类型。
一种解决方法是 constraint subsumption。这意味着(以一种非常手波浪的方式)如果你的概念被写成相同基本约束的结合(或析取),编译器可以规范化表达式以选择“更专业的”。将其应用于您的示例..
template<typename T>
concept printable = requires (T t, std::size_t s)
{
{ t.size() } -> std::convertible_to<std::size_t>;
{ t[s] } -> std::convertible_to<char>;
};
template<typename T>
concept printable_num = printable<T> && requires (T t, std::size_t s)
{
{ t[s] } -> std::same_as<int&>;
};
请注意我们如何使用 printable
将 printable_num
定义为“更具体”的概念。 运行这个例子,我们得到了output you are after.