在 C++ 中推导两个类的共享基数

Ami*_*rsh 6 c++ type-traits c++-experimental

我几乎可以肯定,如果没有反思,我正在寻找的东西就无法完成,而反思还没有出现在语言中。但有时我会对 SO 中的特殊答案感到惊讶,所以让我们尝试一下。

\n

是否可以推导出具有共同共享基类的两种类型的“common_base”,因此以下内容是可能的(伪代​​码! -语言中没有 ,这就是我想要实现的魔力) :common_base_t

\n
template<typename T1, typename T2>\nconst common_base_t<T1, T2>& foo(const T1& a1, const T2& a2) {\n    if(a1 < a2) return a1;\n    return a2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,上面a1的 和a2并不共享 a common_type,只是作为兄弟(共享相同的基数),因此我们不能使用三元运算符。

\n

另请注意,将上述返回类型更改为 并const auto&不能解决问题(它不会编译:auto return type 的推导不一致)。

\n

这是 na\xc3\xafve 实现,要求调用者声明预期的返回类型:

\n
template<typename R>\nconst R& foo(const auto& a1, const auto& a2) {\n    if(a1 < a2) return a1;\n    return a2;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后我们可以这样调用它:

\n
MyString1 s1 = "hello"; // MyString1 derives from std::string\nMyString2 s2 = "world"; // MyString2 also derives from std::string\nstd::cout << foo<std::string>(s1, s2); // ok we return const lvalue ref\n                                       // pointing to one of the above objects\n
Run Code Online (Sandbox Code Playgroud)\n

如果不提供预期的回报值,这可能无法实现,原因有很多。但也许可以通过某种方式实现?

\n

小智 3

标准库std::common_reference<>非常接近您想要的,并且可以说您的foo()函数应该使用什么,因为它清楚地表达了所需的语义:

template<typename T1, typename T2>
std::common_reference_t<const T1&, const T2&> foo(const T1& a1, const T2& a2) {
    if(a1 < a2) return a1;
    return a2;
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,对于这个特定的用例,它不能开箱即用,因为它无法检测公共基础,除非其中一种类型派生于另一种类型。

但是,您可以通过专门提供提示std::common_type。就像这样:

namespace std {
    template<>
    struct common_type<MyString1, MyString2> {
        using type = std::string;
    };
}
Run Code Online (Sandbox Code Playgroud)

它会“正常工作”。您可以在这里看到它的实际效果: https: //gcc.godbolt.org/z/e3PrecPac

编辑: 值得一提的是,根据您的情况,您还可以为std::common_type从给定基础派生的所有类型创建通用专业化:

struct SomeBase {};

namespace std {
    template<std::derived_from<SomeBase> T1, std::derived_from<SomeBase> T2>
    struct common_type<T1, T2> {
        using type = SomeBase;
    };
}
Run Code Online (Sandbox Code Playgroud)

不过,我会对此略加讨论。这是一个潜在的非常广泛和广泛的部分专业化。它很容易导致歧义,特别是如果多次这样做的话。