我有一个库类型,它只能用作全局变量,并且必须是链接器初始化的(即它必须在静态初始化时间之前具有正确的初始值)。我有充分的理由认为,如果我做两件事之一,我会得到我需要的东西:
Type var = { expr, expr };
语法。constexpr
构造函数,并依赖用户将所有实例声明为constexpr
。这些都不是很好,因为它取决于用户不会搞砸了。
没有宏观魔力,有没有办法强制所有类型的实例都是constexpr
?
答案 0 :(得分:1)
创建
template<Type1 value1, Type2 value2>
constexpr MyType make_MyTYpe(/* No args */)
{
return MyType(value1, value2); // call the (private) constexpr constructor
}
如果您的类型仅提供const方法,则用户必须使用const
对象。
const MyType myobject = make_MyType<4, 2>();
来自myobject
的<{const
constexpr
。
答案 1 :(得分:1)
您无法阻止的是用户向创建的任何实例声明const&
。但是,您可以阻止复制和移动实例。现在,您只需强制所有创建的实例都是在需要常量表达式的上下文中创建的。
这是一种强制执行此操作的奇怪方法:让所有实例成为类{模板}的static constexpr
成员。
然后,用户提供了一种获取&#34;变量&#34;的构造函数参数的方法。
struct constructor_params
{
int i;
double d;
};
用户提供的实例必须可以在常量表达式中使用,以便初始化static constexpr
成员。
为了创建不同的实例,我们需要某种标记值来创建包含static constexpr
成员的类模板的不同实例,该成员将作为变量实例。我选择通过让用户提供工厂函数或类型来创建参数来组合标记值和提供constructor_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;
};
为了让用户访问两种方式来创建一个名称的变量,有一个重载的make_variable
函数:
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
,一个用本地类型(函数作用域是为什么需要从类型创建)。
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>();
}