如何使用 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&>;
};

请注意我们如何使用 printableprintable_num 定义为“更具体”的概念。 运行这个例子,我们得到了output you are after.