C++ C++;只能用作constexpr变量的类型

C++ C++;只能用作constexpr变量的类型,c++,c++11,constexpr,C++,C++11,Constexpr,我有一个库类型,它只应该用作全局变量,并且必须是链接器初始化的(即,在静态初始化时间之前,它必须具有正确的初始值)。我有强烈的理由认为,如果我做以下两件事中的一件,我会得到我所需要的: 将其设为,首先放置用户提供的成员,并信任用户将正确数量的表达式传递给类型var={expr,expr}语法 使实现私有化,提供一个constexpr构造函数,并依赖用户将所有实例声明为constexpr 这两个都不好,因为这取决于用户是否把事情搞砸了 除了宏魔法,有没有办法强制一个类型的所有实例都是constex

我有一个库类型,它只应该用作全局变量,并且必须是链接器初始化的(即,在静态初始化时间之前,它必须具有正确的初始值)。我有强烈的理由认为,如果我做以下两件事中的一件,我会得到我所需要的:

  • 将其设为,首先放置用户提供的成员,并信任用户将正确数量的表达式传递给
    类型var={expr,expr}语法
  • 使实现私有化,提供一个
    constexpr
    构造函数,并依赖用户将所有实例声明为
    constexpr
  • 这两个都不好,因为这取决于用户是否把事情搞砸了

    除了宏魔法,有没有办法强制一个类型的所有实例都是
    constexpr

    创建一个

    template<Type1 value1, Type2 value2>
    constexpr MyType make_MyTYpe(/* No args */)
    {
        return MyType(value1, value2); // call the (private) constexpr constructor
    }
    

    myobject
    是来自
    constexpr
    const
    ,您不能阻止的是用户向创建的任何实例声明
    const&
    。但是,可以防止复制和移动实例。现在,您只需要强制所有创建的实例都是在需要常量表达式的上下文中创建的

    这里有一种奇怪的方法来实现这一点:让所有实例都是类(模板)的
    static constexpr
    成员

    然后,用户提供了一种获取“变量”的构造函数参数的方法

    用户提供的实例必须在常量表达式中可用,以便初始化
    static constexpr
    成员

    为了创建不同的实例,我们需要某种类型的标记值来创建类模板的不同实例化,该类模板包含将用作变量实例的
    static constepr
    成员。我选择通过让用户提供一个工厂函数或类型来创建参数,从而将标记值和提供
    constructor\u params
    参数的方式结合起来

    首先,您只希望有
    constexpr
    实例的变量类型:

    // forward declarations useful for friendship
    template<class T>
    struct make_variable_by_type;
    
    template<constructor_params(*fptr)(void)>
    struct make_variable_by_func;
    
    
    struct the_variable
    {
        the_variable(the_variable const&) = delete;
        the_variable(the_variable&&) = delete;
    
    private:
        constexpr the_variable(constructor_params) {}
    
        template<class T>
        friend struct make_variable_by_type;
    
        template<constructor_params(*fptr)(void)>
        friend struct make_variable_by_func;
    };
    
    现在,有两个用法示例。一个使用
    constepr
    函数创建
    构造函数参数
    ,另一个使用本地类型(函数范围是需要从类型创建的原因)

    constexpr构造函数参数make_my_变量()
    {
    返回{42,21.0};
    }
    constexpr auto&x=make_变量();
    int main()
    {
    struct make_my__其他_变量
    {
    静态constexpr构造函数_参数make()
    {
    返回{1,2};
    }
    };
    constexpr auto&x=make_变量();
    }
    
    @Jeffrey:根据上下文,你可能是对的,也可能是错的。我的信念是,至少你真的需要聪明地想象每一种可能的实际情况,在这种情况下,你想要平衡使用的灵活性和使用的限制。这些限制背后的原因是什么?@Jeffrey:由政策强加的。tl;博士未指定静态初始化的内部编译单元顺序。这会导致调用
    constexpr
    构造函数来创建
    const
    变量,这正是我想要阻止的用法。这可能会显示一个问题:通过引用返回,您必须为该变量提供定义,因为它使用了ODR(IIRC). 但是当使用常量表达式时,这并不是您真正想要的。嗯,您实际上可以将该静态数据成员设为私有,并为其提供(
    static constexpr
    )访问器函数。。
    struct constructor_params
    {
        int i;
        double d;
    };
    
    // forward declarations useful for friendship
    template<class T>
    struct make_variable_by_type;
    
    template<constructor_params(*fptr)(void)>
    struct make_variable_by_func;
    
    
    struct the_variable
    {
        the_variable(the_variable const&) = delete;
        the_variable(the_variable&&) = delete;
    
    private:
        constexpr the_variable(constructor_params) {}
    
        template<class T>
        friend struct make_variable_by_type;
    
        template<constructor_params(*fptr)(void)>
        friend struct make_variable_by_func;
    };
    
    template<constructor_params(*fptr)(void)>
    struct make_variable_by_func
    {
        static constexpr the_variable value{fptr()};
    };
    template<constructor_params(*fptr)(void)>
    const the_variable make_variable_by_func<fptr>::value;
    
    template<class T>
    struct make_variable_by_type
    {
        static constexpr the_variable value{T::make()};
    };
    template<class T>
    const the_variable make_variable_by_type<T>::value;
    
    
    template<class T>
    constexpr the_variable const& make_variable()
    {
        return make_variable_by_type<T>::value;
    }
    
    template<constructor_params(*fptr)(void)>
    constexpr the_variable const& make_variable()
    {
        return make_variable_by_func<fptr>::value;
    }
    
    constexpr constructor_params make_my_variable()
    {
        return {42, 21.0};
    }
    
    constexpr auto& x = make_variable<make_my_variable>();
    
    int main()
    {
        struct make_my_other_variable
        {
            static constexpr constructor_params make()
            {
                return {1, 2};
            }
        };
    
        constexpr auto& x = make_variable<make_my_other_variable>();
    }