衍生类中的表达,铿锵与休息

da_*_*m_n 7 c++ gcc clang

最小的例子:

#include <cstddef>
struct B
{
    constexpr static const size_t MAX = 10;
};

struct D : B 
{
    constexpr static const size_t MAX = 20;
};

void use(const B& v)
{
    static_assert(v.MAX == 10, "");
}

template<typename X>
void use2(X&& v)
{
    static_assert(v.template MAX == 20, "");
}

int main ()
{
    D d;
    static_assert(d.MAX == 20, "");
    use(d);
    use2(d);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

GCC(v5.4 ... v7.3):编译好(任何级别的优化和-Wall -Wextra -pedantic)ICC/MSVC:编译好(在godbolt.org上尝试各种版本)

CLANG(v4 ... v6):错误:static_assert表达式不是整数常量表达式static_assert(v.MAX == 10,"");

编辑(改写问题):

在我看来,clang的行为是最不令人惊讶的(或更直观).鉴于它的失败编译上面的代码中仅有的编译器,我想了解哪两个行为是正确的,为什么呢?

编辑2:

通过添加模板函数判断,gcc看起来使用参数的声明类型,并确定使用哪个constexpr成员,而不管传入的是什么.

如果通过值,clang也会将MAX评估为常量表达式.在这种情况下,很明显为什么v.MAX == 10对于非模板化函数的所有编译器都是正确的.

编辑3(甚至更短的版本):仍然没有编译clang

#include <cstddef>

struct B
{
     constexpr static const size_t MAX = 10;
};

void use(const B& v)
{
    static_assert(v.MAX == 10, "");
}

template<typename X>
void use2(X&& v)
{
    static_assert(v.template MAX == 10, "");
}

int main ()
{
    B v;
    static_assert(v.MAX == 10, "");
    use(v);
    use2(v);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

xsk*_*xzr 2

叮当是正确的。

v.MAX == 10评估v,这是一个没有预先初始化的引用。这在常量表达式中是不允许的。

请注意,即使MAX是静态成员,v在 的求值过程中仍会求值v.MAX

您可以使用类类型来访问MAX以避免评估v,例如

void use(const B& v)
{
    static_assert(B::MAX == 10, "");
               // ^^^
}

template<typename X>
void use2(X&& v)
{
    static_assert(std::remove_reference_t<X>::MAX == 10, "");
               // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
Run Code Online (Sandbox Code Playgroud)