constexpr类的设计:合并constexpr和非constexpr版本?

21

考虑一个在运行时仅包装某个值的类:

template <typename Type>
class NonConstValue 
{
    public:
        NonConstValue(const Type& val) : _value(val) {;}
        Type get() const {return _value;}
        void set(const Type& val) const {_value = val;}
    protected:
        Type _value;
};

以及它的constexpr版本:

template <typename Type>
class ConstValue 
{
    public:
        constexpr ConstValue(const Type& val) : _value(val) {;}
        constexpr Type get() const {return _value;}
    protected:
        const Type _value;
};

问题1:您能确认constexpr版本的设计是否正确吗?

问题2:如何将两个类混合成一个名为Value的单一类,该类可以在编译时或运行时进行constexpr构造,并且其值可以在运行时或编译时使用get()函数获取?

编辑: 问题3:如果get().cpp文件中定义,如果我希望get()在不是constexpr的情况下内联,那么函数的正确声明是什么?是

constexpr inline Type get();
或者
inline constexpr Type get()

还是其他什么?


9
constexpr 函数可以在编译时或运行时调用。 - chris
1
我认为非静态的constexpr成员函数存在缺陷,因为它们总是暗示着一个const函数限定符,即constexpr foo bar();constexpr foo bar() const;是相同的声明。对于非成员函数没有这样的要求,即constexpr foo bar(T&);或constexpr foo bar(T&&);都可以接受非常量的T(并且可能涉及到非常量限定的类类型的常量表达式)。所以要注意这一点。 - Luc Danton
不,constexpr函数可以是非const的,因为在对象被创建并且它的生成“值”处于constexpr上下文中(显式或放入模板中)之前,该对象仍处于流动状态,并且容易被修改。直到这一点,用于该对象的函数调用必须const的。 - Adrian
2个回答

36

只需将可能成为常量表达式的每个函数添加constexpr修饰符。

template <typename Type>
class Value 
{
public:
    constexpr Value(Type const& val) : _value(val) {}
    constexpr Type const& get() const {return _value;}
    void set(Type const& val) {_value = val;}
protected:
    Type _value;
};

你不需要一个const和一个non-const版本,因为可以通过使用带有constnon-const类型的模板Value来实现。

你不需要一个constexpr和一个non-constexpr版本,constexpr表示潜在的常量表达式,该表达式最终是否成为常量表达式取决于它的参数。该表达式最终是否在编译时被求值取决于上下文和实现方式。


1
+1,正是我想说的。甚至在constexpr对象内部也允许使用mutable - Potatoswatter
非常挑剔,但 constexpr 是一个说明符,而不是一个声明符。 - aschepler
@aschepler:谢谢,我知道它不是一个修饰符,但我缺少正确的术语。 - K-ballo
1
@Vincent:添加 inline 不会影响函数是否被内联。如果它在另一个 .cpp 文件中,则可能不会被内联,因为编译器无法从外部看到其定义。 - K-ballo
注意:将 get() 声明为 constexprconst 是不必要的。前者暗示了后者。 - jogojapan
尽管constexpr函数不能拥有静态局部变量等其他特性,但是拥有两个独立的函数仍然很有用。 - user90843

3

您的constexpr类设计得很好,只是构造函数的名称打错了(应该是ConstValue而不是Value)。但我相信这只是一个笔误。

您的constexpr版本的实例既可以作为编译时对象又可以作为运行时对象使用。

template <typename Type>
class ConstValue
{
    public:
        constexpr ConstValue(const Type& val) : _value(val) {;}
        constexpr Type get() const {return _value;}
    protected:
        const Type _value;
};

int main(int argc, char* argv[])
{
    int x[ConstValue<int>(3).get()];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接