c ++静态多态(CRTP)在评估“静态constexpr”时

时间:2019-03-19 13:27:34

标签: c++ visual-c++ metaprogramming crtp static-polymorphism

我需要访问static constexpr,我提出的一个解决方案适用于gcc(live example),而不适用于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 ++的一个错误,但是任何人都对如何实现val中定义的Base作为valDrvd的值有了不同的想法。 vc ++不会抱怨的方式?

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

3 个答案:

答案 0 :(得分:1)

您可以使用一种方法:

#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

答案 1 :(得分:1)

您的问题不是私人/朋友声明(即使 “ val”是公开的),您的问题是

的实例化期间
static constexpr bool val = Drvd::val

Drvd仍然是不完整的类型。 有关如何解决特质类的问题,请参见下面的问题/答案。

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

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

答案 2 :(得分:0)

每个@David,问题与Face不完整有关,因为它在完成Base的定义之前就进入了Face

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

以下(React's documentation for setState)显示了如何解决此问题,同时将每个类封装到自己的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;
}

总体思路是,对于constexpr需要从Base访问的每个Derived,我们可以创建一个封装变量的单个类,然后为每个{使用Derived的{​​1}}。