英文:
Making type trait work for all derived types
问题
我有一个类型特性和概念,用于检查std::variant
是否能够容纳给定的类型T
。现在我有一个类型variant2
,它派生自std::variant
,我想在新的variant2
类型中使用这个类型特性。如何优雅地实现这一目标?
这不起作用(演示):
#include <variant>
#include <string>
#include <iostream>
#include <concepts>
#include <type_traits>
template<typename T, typename Variant>
struct variant_type;
template<typename T, typename... Args>
struct variant_type<T, std::variant<Args...>>
: public std::disjunction<std::is_same<T, Args>...> {};
template<typename T, typename Variant>
concept is_variant_type = variant_type<T, Variant>::value;
template <typename... Ts>
struct variant2 : public std::variant<Ts...> {
};
variant2<std::monostate, int, bool, std::string> var;
int main() {
using T = std::string;
if constexpr (is_variant_type<T, decltype(var)>) {
std::cout << "Worked!" << std::endl;
}
}
"Worked" 从未出现在屏幕上,这显然是因为默认的类型特性被SFINAED。
英文:
I have a type trait and concept which checks if an std::variant
can hold a given type T
. Now I have a type variant2
which derives from std::variant
, and I want to use that type trait with the new variant2
type. How can I accomplish this elegantly?
This doesn't work (Demo):
#include <variant>
#include <string>
#include <iostream>
#include <concepts>
#include <type_traits>
template<typename T, typename Variant>
struct variant_type;
template<typename T, typename... Args>
struct variant_type<T, std::variant<Args...>>
: public std::disjunction<std::is_same<T, Args>...> {};
template<typename T, typename Variant>
concept is_variant_type = variant_type<T, Variant>::value;
template <typename... Ts>
struct variant2 : public std::variant<Ts...> {
};
variant2<std::monostate, int, bool, std::string> var;
int main() {
using T = std::string;
if constexpr (is_variant_type<T, decltype(var)>) {
std::cout << "Worked!" << std::endl;
}
}
"Worked" never appears on the screen which is obvious because the default type trait is SFINAED.
答案1
得分: 5
你只需通过表达你的模板必须继承自std::variant
来修复你的专业化:
#include <concepts>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
template <typename T, typename Variant>
struct variant_type;
template <typename T, template <typename...> typename Var, typename... Args>
struct variant_type<T, Var<Args...>>
: public std::conjunction<
std::disjunction<std::is_same<T, Args>...>,
std::is_base_of<std::variant<Args...>, Var<Args...>>> {};
template <typename T, typename Variant>
concept is_variant_type = variant_type<T, Variant>::value;
template <typename... Ts>
struct variant2 : public std::variant<Ts...> {};
variant2<std::monostate, int, bool, std::string> var;
int main() {
using T = std::string;
if constexpr (is_variant_type<T, decltype(var)>) {
std::cout << "Worked!" << std::endl;
}
}
我只翻译了代码部分,没有包括问题中的附加信息。
英文:
You can just fix your specialization by expressing that your template must inherit from std::variant
#include <concepts>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
template <typename T, typename Variant>
struct variant_type;
template <typename T, template <typename...> typename Var, typename... Args>
struct variant_type<T, Var<Args...>>
: public std::conjunction<
std::disjunction<std::is_same<T, Args>...>,
std::is_base_of<std::variant<Args...>, Var<Args...>>> {};
template <typename T, typename Variant>
concept is_variant_type = variant_type<T, Variant>::value;
template <typename... Ts>
struct variant2 : public std::variant<Ts...> {};
variant2<std::monostate, int, bool, std::string> var;
int main() {
using T = std::string;
if constexpr (is_variant_type<T, decltype(var)>) {
std::cout << "Worked!" << std::endl;
}
}
I just added a conjunction to achieve that and we'are done.<br>
Live<br>
[EDIT] sorry, it's just a bit more complicated: I added a template template parameter that implies that your inherited class has exactly the same template parameters than the base one, which might be restrictive.
答案2
得分: 2
以下是您要翻译的内容:
由于 variant2
继承了 std::variant
,您可以通过以下辅助函数提取其基本的 variant
类型:
template<typename... Args>
auto as_variant(const std::variant<Args...>&) -> std::variant<Args...>;
template<typename T>
struct to_variant;
template<typename T>
requires requires (const T& t) { as_variant(t); }
struct to_variant<T> {
using type = decltype(as_variant(std::declval<const T&>()));
};
然后稍微修改 is_variant_type
概念:
template<typename T, typename Variant>
concept is_variant_type =
variant_type<T, typename to_variant<Variant>::type>::value;
或者更简单地,直接定义 is_variant_type
如下:
template<typename T, typename Variant>
concept is_variant_type = requires (const Variant& var) {
[]<typename... Args>(const std::variant<Args...>&)
requires (std::same_as<T, Args> || ...)
{ }(var);
};
英文:
Since variant2
inherits std::variant
, you can extract its base variant
type through the following helper function
template<typename... Args>
auto as_variant(const std::variant<Args...>&) -> std::variant<Args...>;
template<typename T>
struct to_variant;
template<typename T>
requires requires (const T& t) { as_variant(t); }
struct to_variant<T> {
using type = decltype(as_variant(std::declval<const T&>()));
};
Then slightly modify the is_variant_type
concept
template<typename T, typename Variant>
concept is_variant_type =
variant_type<T, typename to_variant<Variant>::type>::value;
Or more simply, just define is_variant_type
directly as
template<typename T, typename Variant>
concept is_variant_type = requires (const Variant& var) {
[]<typename... Args>(const std::variant<Args...>&)
requires (std::same_as<T, Args> || ...)
{ }(var);
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论