我在修改现有代码时偶然发现别名声明创建了
std::optional<void>
。它来自这样的模板代码:
using ret_t = std::invoke_result_t<Fn, Args...>;
using opt_ret_t = std::optional<ret_t>;
稍后代码会区分返回类型为(非)void 的情况,因此永远不会创建实际的可选对象。为了确保我没有遗漏某些内容,我在该代码分支中添加了一个断言,并且所有内容都可以编译:
static_assert(std::is_same_v<opt_ret_t, std::optional<void>>);
cppreference 说: 没有可选的引用、函数、数组或 cv void;如果程序用这样的类型实例化一个可选项,那么它就是格式错误的。 因此,不管编译器不抱怨这段代码是否格式错误?
在某些特定情况下,(类)模板会被隐式实例化:请参阅 [temp.inst],尽管在某些情况下,它可能会因实现而异。 在任何情况下,仅仅提及 template-id 都不会导致实例化;通常,当类型需要完整时,就会发生这种情况。
在 C++20 中,可以声明带有 constraints 的模板,即使模板专门化仅被命名,这些约束也会生效:
template<class T> requires !std::is_void_v<T>
struct foo {…};