假设我有一个带有
consteval
构造函数的类,可确保编译时的值有效。 (还有一个 std::expected-returning
工厂方法可以在运行时验证其参数,但这与这个问题无关。)
class ConstevalConstructible {
public:
consteval ConstevalConstructible(int value) : value_(value) {
// Validate value and fail compile if invalid.
}
// Copyable, movable, et cetera
private:
int value_;
}
现在假设我有一个可以保存任何值的通用包装结构:
template <typename T>
struct Wrapper {
template <typename... Args>
constexpr Wrapper(Args&&... args) : inner(std::forward<Args>(args)...) {}
T inner;
};
由于
constexpr
允许在常量上下文中调用构造函数,因此包装器对于运行时构造和 constexpr 构造都可以正常工作:
// Fine
Wrapper<RuntimeConstructible> foo{runtime_value};
// Also fine: Wrapper's constexpr constructor is evaluated at compile
// time and thus the ConstexprConstructible's constructor is too.
constexpr Wrapper<ConstexprConstructible> bar{42};
将
ConstevalConstructible
与Wrapper
一起使用时会出现问题:
// Fails to compile: the constexpr Wrapper constructor is not an
// immediate function, so it cannot invoke ConstevalConstructible's
// constructor using arguments that are not (within its body)
// constexpr.
Wrapper<ConstevalConstructible> foo{5};
// Doesn't fix the problem from the compiler's point of view.
constinit Wrapper<ConstevalConstructible> foo{5};
// This does work as long as ConstevalConstructible is movable or
// copyable, but gets annoying.
Wrapper<ConstevalConstructible> bar{ConstevalConstructible{5}};
问题是,虽然
constexpr
求值从外到内传播(变量声明上的 constexpr
导致 Wrapper
的构造函数在编译时求值,进而导致 ConstexprConstructible
的构造函数编译时评估),构造函数consteval
-ness将需要从内到外传播(ConstevalConstructible
的构造函数为consteval
必须导致Wrapper
的构造函数也为consteval
,所以立即评估 Wrapper
的整个构造)。
这感觉类似于
noexcept
的工作方式,其中可以根据所包含的类型来指定方法是否抛出。但是,我不知道有类似的方法可以使构造函数或函数有条件地consteval
。我考虑添加 consteval
重载,但我不确定如何限制它:
template <typename T>
struct Wrapper {
template <typename... Args>
constexpr Wrapper(Args&&... args) : inner(std::forward<Args>(args)...) {}
template <typename... Args>
consteval Wrapper(Args&&... args)
requires requires { /** What would I put here? **/ }
: inner(std::forward<Args>(args)...) {}
T inner;
};
这在 C++20 中可以解决吗?如果没有,有计划在未来版本中出现吗?
这个确切的问题已作为针对 C++20 的缺陷报告被解决了,因此最终应该可以在任何出售
consteval
的地方使用。