【发布时间】:2019-06-29 05:38:30
【问题描述】:
由于 C++20 概念尚未标准化,我使用 static_assert 作为临时概念检查,以便在不满足类型要求时提供有用的错误消息。在这种特殊情况下,我有一个函数,它要求一个类型在获取其结果类型之前是可调用的:
template <typename F, typename... Args>
void example() {
static_assert(std::is_invocable_v<F, Args...>, "Function must be callable");
using R = std::invoke_result_t<F, Args...>;
// ...
}
另外,我要求 callable 的结果必须是某种std::optional,但我不知道 optional 会持有什么类型,所以我需要从中获取该类型:
using R = // ...
using T = typename R::value_type; // std::optional defines a value_type
但是,如果类型 R 没有 value_type,这将失败,例如如果它不是预期的std::optional。我想先用static_assert 来检查它,如果断言失败,还有另一个很好的错误消息。
我可以用std::is_same_v 之类的东西检查确切的类型,但在这种情况下,我不知道确切的类型。我想检查R 是std::optional 的一些 实例,但没有指定它必须是哪个 实例。
一种方法是使用辅助特征:
template <typename T>
struct is_optional { static constexpr bool value = false; };
template <typename T>
struct is_optional<std::optional<T>> { static constexpr bool value = true; };
template <typename T>
constexpr bool is_optional_v = is_optional<T>::value;
……然后我可以写:
static_assert(is_optional_v<R>, "Function's result must be an optional");
这行得通,但是仅仅为了像这样的一次性检查而用辅助特征污染我的命名空间似乎有点尴尬。我不希望在其他任何地方都需要is_optional,尽管我可以想象可能会以其他一次性特征结束,例如is_variant 或is_pair。
所以我想知道:有更简洁的方法吗?我可以在 std::optional 的实例上进行模式匹配,而无需定义 is_optional 特征及其部分专业?
【问题讨论】:
-
“简洁”是指更少的行,还是意味着更少的命名空间范围声明?
-
您可以创建一个可重用的 trait,允许您定义
constexpr bool is_optional_v = is_template_of<std::optional, T>::value;并且可以重用于一对/变体与一个衬垫。
标签: c++ templates c++17 template-meta-programming