Clang 18 和来自多个基地的操作员过载

clang 18 and operator overloads from multiple bases

提问人:Konstantin Lazukin 提问时间:10/23/2023 更新时间:10/23/2023 访问量:111

问:

我已将 clang 从 ver 14 升级到最新版本(主干上的 18),似乎我在代码中遇到的唯一问题是来自多个基类的运算符继承(下面的示例和对 godbolt 的引用)。这是一个简化的示例,我有一个最终的向量类,该类派生了一些添加功能的 mixin。在本例中,这些混合函数是向量-标量乘法和向量-向量乘法,以向量点积的形式实现。这两种混合都相加,但这两个运算符都专门用于处理特定类型的类型,因此不应有任何歧义。直到现在,这一直很有效。所以我的问题是 - 这个新错误是某些标准要求的实现,还是这只是编译器测试版中的一个错误,我的代码没问题?operator*

https://godbolt.org/z/ca8Yefjdc

#include <cstddef>
#include <type_traits>
#include <array>

template<
    typename T, size_t N,
    template <typename, size_t> typename FinalTemplate
>
struct VectorData
{
    std::array<T, N> data;
};

template<
    typename T, size_t N,
    template <typename, size_t> typename FinalTemplate
>
struct VectorScalarMultiplication
{
    using Final = FinalTemplate<T, N>;

    template<typename U, typename Enable = std::enable_if_t<(
        std::is_integral_v<U> || std::is_floating_point_v<U>
    )>>
    Final operator*(const U value) const
    {
        auto copy = static_cast<const Final&>(*this);
        for (size_t i = 0; i != N; ++i)
        {
            copy.data[i] *= value;
        }

        return copy;
    }
};



template<
    typename T, size_t N,
    template <typename, size_t> typename FinalTemplate
>
struct VectorVectorMultiplication
{
    using Final = FinalTemplate<T, N>;

    T operator*(const Final& b) const
    {
        auto& a = static_cast<const Final&>(*this);
        T r{};
        for (size_t i = 0; i != N; ++i)
        {
            r += a.data[i] * b.data[i];
        }

        return r;
    }
};

template<typename T, size_t N>
struct Vector
    : public VectorData<T, N, Vector>
    , public VectorScalarMultiplication<T, N, Vector>
    , public VectorVectorMultiplication<T, N, Vector>
{
};

int main()
{
    Vector<float, 3> a;
    return static_cast<int>(a * a);
}

如果有帮助,将这些行添加到最终类中可以解决问题,但会破坏 mixin 的整个想法:

    using VectorScalarMultiplication<T, N, Vector>::operator*;
    using VectorVectorMultiplication<T, N, Vector>::operator*;
C 模板 多继承 Mixins CLang++

评论


答:

6赞 cigien 10/23/2023 #1

这是 Clang 中一个长期存在的错误,其中未诊断出基类中的模棱两可的成员。上面链接的 bug 报告中的示例使用了 ,但该错误也发生在其他运算符重载中(尽管正确诊断了常规命名函数)。该错误最近已修复。operator()

所以你的代码从来都不应该按照它编写的方式工作,现在它不起作用,因为 Clang 错误已经修复。

4赞 Brian Bi 10/23/2023 #2

当编译器解释表达式时,它通过查找成员和非成员候选项来实现。a * a

在查找的成员部分,编译器在左操作数类的作用域内(即在类的作用域中)执行查找。operator*Vector

当成员名称查找发现从不同基类继承的不同实体时,程序的格式不正确。情况一直如此,但似乎旧版本的 Clang 没有诊断出它。你的代码当时不应该被接受,但无论如何都是。

显然,当有多个 mixin 贡献具有相同名称的成员时,mixin 模式不会产生理想的结果。在这种特殊情况下,如果将每个人都定义为非成员隐藏朋友而不是成员,则可以获得更好的结果。在这种情况下,成员名称查找规则不适用,而是使用与参数相关的查找。无需使用声明operator*