c ++静态多态性(CRTP)在评估`static constexpr`时导致类型不完整

c++ static polymorphism (CRTP) Resulting in incomplete type when evaluating a `static constexpr`

我需要访问 static constexpr 并且我将一个解决方案与 gcc (live example) but not with vc++ (live example) 结合使用。

代码如下:

template<class Drvd>
class Base
{
public:
    static constexpr bool val = Drvd::val;
};

class Derived : public Base<Derived>
{
    friend class Base;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val << std::endl;
}

所以这是 vc++ 的一个错误,但是任何人都知道如何实现 Base 中定义的 val 作为 val 中的值Drvd vc++ 不会抱怨的另一种方式?

编辑: 请注意,结果与变体相同:friend class Base<Derived>; 而不是 friend class Base;

您可以使用一种方法:

#include <iostream>

template<class Drvd>
class Base
{
public:
    static constexpr bool val() { return Drvd::val;  }
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true;
};

int main()
{
    std::cout << Derived::Base::val() << std::endl;
}

实例:https://rextester.com/IHR24393

你的问题不是 private/friend 声明(即使 "val" 是 public),你的问题是在实例化

期间
static constexpr bool val = Drvd::val

Drvd 仍然是不完整的类型。 请参阅下文 question/answer 了解如何使用特征 类.

解决此问题

C++ static polymorphism (CRTP) and using typedefs from derived classes

P.S。事实上,我只是将您的问题标记为重复

Per @David,问题与 Face 不完整有关,因为它在完成 Face.

的定义之前进入 Base

但是,@David 链接到的解决方案有点旧,并且遗漏了一些我们可以利用的技巧。即,@m.s。向我们展示了 static constexpr 函数是好的 - 并且也是基于我自己的实验 - 我们真的只需要处理 static constexpr 变量的这种特殊情况,也许还有从 Derived 访问的类型。

以下 (live example) 展示了如何解决这个问题,同时将每个 class 封装到它自己的 h 文件中,使其更清晰:

#include <iostream>

// Begin: h-file of Base
template<class Drvd>
class ConstValue;

template<class Drvd>
class Base
{
public:
    static constexpr bool val = ConstValue<Drvd>::val;
};
// End: h-file of Base

// Begin: h-file of Derived
class Derived;

template<>
class ConstValue<Derived>
{
public:
    static constexpr bool val = true;
};

class Derived : public Base<Derived>
{
    friend class Base<Derived>;
private:
    static constexpr bool val = true; // optional
};
// End: h-file of Derived

// Main
int main()
{
    std::cout << Derived::Base::val << std::endl;
}

一般的想法是,对于 Base 需要从 Derived 访问的每个 constexpr,我们可以创建一个封装变量的单个 class,然后为每个使用 Base.

Derived 重载 class