如何结合std::is_invocable与std::variant、std::holds_alternative做调用检查
问题描述
我定义了如下std::variant类型:
using Value = std::variant<bool, float>;
std::holds_alternative可针对该变体包含的bool、float类型调用,但无法针对int等其他类型调用。现在想检查给定类型T时,std::holds_alternative<T>(const Value&)是否可调用,尝试了如下模板函数但编译失败:
template<class T> void check() { if (std::is_invocable_v<decltype(std::holds_alternative<bool>), const Value&>) { std::cout << "callable"; } else { std::cout << "not callable"; } }
请问正确的语法是什么?
解决方案
你的代码核心问题有两个:一是硬编码了bool类型,没有复用模板参数T;二是未使用if constexpr来隔离非法分支,导致非备选类型触发编译错误。以下是两种正确实现方式:
方式一:基于std::is_invocable_v的直接判断
利用if constexpr在编译期丢弃非法分支,同时将模板参数T代入std::holds_alternative进行判断:
#include <variant> #include <iostream> #include <type_traits> using Value = std::variant<bool, float>; template<class T> void check() { if constexpr (std::is_invocable_v<decltype(std::holds_alternative<T>), const Value&>) { std::cout << "callable\n"; } else { std::cout << "not callable\n"; } } int main() { check<bool>(); // 输出callable check<float>(); // 输出callable check<int>(); // 输出not callable }
关键说明
decltype(std::holds_alternative<T>)获取的是针对T实例化后的std::holds_alternative函数类型,结合const Value&参数,std::is_invocable_v能准确判断调用合法性。if constexpr是必须的:当T不是Value的备选类型时,std::holds_alternative<T>的实例化会触发标准规定的格式错误,if constexpr会在编译期跳过不成立的分支,避免错误代码被实例化。
方式二:直接检查类型是否为变体备选类型
既然std::holds_alternative<T>可调用的前提是T是variant的备选类型之一,我们可以直接判断类型归属:
#include <variant> #include <iostream> #include <type_traits> using Value = std::variant<bool, float>; // 通用工具:判断类型T是否是Variant的备选类型 template<class T, class Variant> struct is_variant_alternative : std::false_type {}; template<class T, class... Args> struct is_variant_alternative<T, std::variant<Args...>> : std::disjunction<std::is_same<T, Args>...> {}; template<class T, class Variant> constexpr bool is_variant_alternative_v = is_variant_alternative<T, Variant>::value; template<class T> void check() { if constexpr (is_variant_alternative_v<T, Value>) { std::cout << "callable\n"; } else { std::cout << "not callable\n"; } } int main() { check<bool>(); // 输出callable check<float>(); // 输出callable check<int>(); // 输出not callable }
这种方式更直观,直接从类型归属角度判断,避免了对std::holds_alternative的间接调用检查。
内容的提问来源于stack exchange,提问作者gimmeamilk
相关产品推荐
相关产品推荐

