使类型特性适用于所有派生类型

huangapple go评论65阅读模式
英文:

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 &lt;variant&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;concepts&gt;
#include &lt;type_traits&gt;

template&lt;typename T, typename Variant&gt;
struct variant_type;

template&lt;typename T, typename... Args&gt;
struct variant_type&lt;T, std::variant&lt;Args...&gt;&gt; 
    : public std::disjunction&lt;std::is_same&lt;T, Args&gt;...&gt; {};

template&lt;typename T, typename Variant&gt;
concept is_variant_type = variant_type&lt;T, Variant&gt;::value;

template &lt;typename... Ts&gt;
struct variant2 : public std::variant&lt;Ts...&gt; {
};

variant2&lt;std::monostate, int, bool, std::string&gt; var;

int main() {
    using T = std::string;

    if constexpr (is_variant_type&lt;T, decltype(var)&gt;) {
        std::cout &lt;&lt; &quot;Worked!&quot; &lt;&lt; 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 &lt;concepts&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;type_traits&gt;
#include &lt;variant&gt;

template &lt;typename T, typename Variant&gt;
struct variant_type;

template &lt;typename T, template &lt;typename...&gt; typename Var, typename... Args&gt;
struct variant_type&lt;T, Var&lt;Args...&gt;&gt;
    : public std::conjunction&lt;
          std::disjunction&lt;std::is_same&lt;T, Args&gt;...&gt;,
          std::is_base_of&lt;std::variant&lt;Args...&gt;, Var&lt;Args...&gt;&gt;&gt; {};

template &lt;typename T, typename Variant&gt;
concept is_variant_type = variant_type&lt;T, Variant&gt;::value;

template &lt;typename... Ts&gt;
struct variant2 : public std::variant&lt;Ts...&gt; {};

variant2&lt;std::monostate, int, bool, std::string&gt; var;

int main() {
    using T = std::string;

    if constexpr (is_variant_type&lt;T, decltype(var)&gt;) {
        std::cout &lt;&lt; &quot;Worked!&quot; &lt;&lt; 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&lt;typename... Args&gt;
auto as_variant(const std::variant&lt;Args...&gt;&amp;) -&gt; std::variant&lt;Args...&gt;;

template&lt;typename T&gt;
struct to_variant;

template&lt;typename T&gt;
  requires requires (const T&amp; t) { as_variant(t); }
struct to_variant&lt;T&gt; {
  using type = decltype(as_variant(std::declval&lt;const T&amp;&gt;()));
};

Then slightly modify the is_variant_type concept

template&lt;typename T, typename Variant&gt;
concept is_variant_type = 
  variant_type&lt;T, typename to_variant&lt;Variant&gt;::type&gt;::value;

Or more simply, just define is_variant_type directly as

template&lt;typename T, typename Variant&gt;
concept is_variant_type = requires (const Variant&amp; var) {
  []&lt;typename... Args&gt;(const std::variant&lt;Args...&gt;&amp;) 
    requires (std::same_as&lt;T, Args&gt; || ...)
  { }(var);
};

Demo

huangapple
  • 本文由 发表于 2023年6月12日 22:47:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76457805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定