是否可以定义一个函数,通过专门化
std::variant
来检查其模板化参数,而不实际包含 <variant>
?当然,为了使实现有意义,变体类型需要完整,但问题是在使用它之前定义这样的函数。
SFINAE 可用于检测变体相似性,因此某些
std::enable_if
或 if constexpr
构造可用于定义分支条件:
#include <type_traits>
template<typename T, typename = void> struct is_variant : std::false_type {};
template<typename T> struct is_variant<T, std::void_t<decltype(std::declval<T>().valueless_by_exception())>> : std::true_type {};
template<typename T>
int get_size_if_variant() {
if constexpr (is_variant<T>::value) {
return std::variant_size_v<T>; // fails to compile: 'variant_size_v' is not a member of 'std'
}
return -1;
}
#include <variant>
#include <iostream>
int main() {
std::cout << get_size_if_variant<std::variant<int, float, std::string>>() << std::endl;
std::cout << get_size_if_variant<bool>() << std::endl;;
return 0;
}
这对于 C++17 来说可能吗?
如果您出于某种原因不想在创建类型特征和使用该头文件中的定义的函数之前
#include<variant>
,您可以通过创建另一个新特征来解决它。我不会将第一个特征称为 is_variant
,因为这不是它要检查的内容,但我假设这里将使用该名称。
您可以创建一个仅返回模板参数计数的特征:
template <class T>
struct template_argument_count
: std::integral_constant<std::size_t, 0> {};
template <template <class...> class T, class... Args>
struct template_argument_count<T<Args...>>
: std::integral_constant<std::size_t, sizeof...(Args)> {};
template <class T>
inline constexpr std::size_t template_argument_count_v =
template_argument_count<T>::value;
那么你的函数可以是:
inline constexpr auto not_a_variant = static_cast<std::size_t>(-1);
template<typename T>
std::size_t get_size_if_variant() {
if constexpr (is_variant<T>::value) {
return template_argument_count_v<T>; // new trait used here
}
return not_a_variant;
}