将派生类中的参数类型限制为适应基类的能力。

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

Constraining parameter type in derived class to fit capabilities of base class

问题

我有一个名为`variant2`的类型,它派生自`std::variant`。现在我想要能够提前捕获潜在的赋值错误,以防分配的类型与其中一个变体类型不匹配。

然而,我想出的方法存在一个问题,即内部`std::variant`的`typedef`直到右括号才完整,所以我无法通过一个概念来传递它。我有哪些备选方案?

(注意:在实际生产代码中,函数`assign`要复杂得多,因此我想为了用户友好性而能够提前捕获错误。)

[演示][1]

#include
#include
#include
#include <type_traits>
#include

template <typename T, typename Variant>
struct is_variant_type;

template <typename T, template <typename...> typename Var, typename... Args>
struct is_variant_type<T, Var<Args...>>
: public std::disjunction<std::is_same<T, Args>...> {};

template <typename T, typename Variant>
concept variant_type = is_variant_type<T, Variant>::value;

template
struct variant2 : public std::variant<std::monostate, int, T>
{
using inner_variant_type = variant2::variant;

template <variant_type<inner_variant_type> U>
auto assign(const U& arg) 
{
    *this = arg;
}

};

int main()
{
variant2std::string var;
var.assign(2);
}


产生的错误:

    <source>:19:42: 错误:对不完整类型“struct variant2<T>”的无效使用
       19 |     using inner_variant_type = variant2::variant;
          |                                          ^~~~~~~
    <source>:18:8: 注意:直到右括号才完成对“struct variant2<T>”的定义
       18 | struct variant2 : public std::variant<std::monostate, int, T> {
          |        ^~~~~~~~
    <source>:21:28: 错误:在此作用域中未声明“inner_variant_type”;你是不是要说“is_variant_type”?
       21 |     template <variant_type<inner_variant_type> U>
          |                            ^~~~~~~~~~~~~~~~~~
          |                            is_variant_type

等等。

[1]: https://godbolt.org/#z:OYLghAFBqd5QCxAYwPYBMCmBRdBLAF1QCcAaPECAMzwBtMA7AQwFtMQByARg9KtQYEAysib0QXACx8BBAKoBnTAAUAHpwAMvAFYTStJg1DIApACYAQuYukl9ZATwDKjdAGFUtAK4sGe1wAyeAyYAHI%2BAEaYxBIAbKQADqgKhE4MHt6%2BekkpjgJBIeEsUTFc8XaYDmlCBEzEBBk%2Bfly2mPZ5DDV1BAVhkdFxtrX1jVktCsM9wX3FA2UAlLaoXsTI7BzmAMzByN5YANQmm25oDGsJBApH2CYaAIJbO3uYh8dOE8SYrNe3D2bbZ2erzcH2CwB%2B90egK8ByObgIAE8EpgAPoEYhMQhXTY3SH/J4wl5wgBudTwhgIEIe9wImBYCQMtOBiORzDY%2BwAKqR9izG...

英文:

I have a type variant2 derived from std::variant. Now I want to be able to early capture potential assignment errors in case the assigned type doesn't match one of the variants types.

However, the way I came up with suffers from the issue that the typedef of the inner std::variant is incomplete until the closing braces, so I can't pass that through a concept. What alternatives do I have?

(Note: In production code the function assign is a lot more complicated, hence I want to be able to capture errors for the sake of user-friendliness early.)

Demo

#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 is_variant_type;

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

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

template &lt;typename T&gt;
struct variant2 : public std::variant&lt;std::monostate, int, T&gt; 
{
    using inner_variant_type = variant2::variant;

    template &lt;variant_type&lt;inner_variant_type&gt; U&gt;
    auto assign(const U&amp; arg) 
    {
        *this = arg;
    }
};

int main() 
{
    variant2&lt;std::string&gt; var;
    var.assign(2);
}

Yields:

&lt;source&gt;:19:42: error: invalid use of incomplete type &#39;struct variant2&lt;T&gt;&#39;
   19 |     using inner_variant_type = variant2::variant;
      |                                          ^~~~~~~
&lt;source&gt;:18:8: note: definition of &#39;struct variant2&lt;T&gt;&#39; is not complete until the closing brace
   18 | struct variant2 : public std::variant&lt;std::monostate, int, T&gt; {
      |        ^~~~~~~~
&lt;source&gt;:21:28: error: &#39;inner_variant_type&#39; was not declared in this scope; did you mean &#39;is_variant_type&#39;?
   21 |     template &lt;variant_type&lt;inner_variant_type&gt; U&gt;
      |                            ^~~~~~~~~~~~~~~~~~
      |                            is_variant_type

etc.

答案1

得分: 4

You are missing a typename keyword, for the dependent type variant2::variant, in the alias declaration inside the class variant2.

Additionally, you have to mention which operator=, that you meant at the line *this = var;, which is by default not visible to the child. You can have more read here: https://stackoverflow.com/questions/1567730/inheritance-and-templates-in-c-why-are-inherited-members-invisible

template <typename T>
struct variant2 : public std::variant<std::monostate, int, T> 
{
    using inner_variant_type = typename variant2::variant;  // required 

    // required to mention that the operator= is from the parent !!
    using std::variant<std::monostate, int, T>::operator=;

    template <variant_type<inner_variant_type> U>
    auto assign(const U& var) {
        *this = var;
    }
};

See a demo

英文:

You are missing a typename keyword, for the dependent type variant2::variant, in the alias declaration inside the class variant2.

Additionally, you have to mention which operator=, that you meant at the line *this = var;, which is by default not visible to the child. You can have more read here: https://stackoverflow.com/questions/1567730/inheritance-and-templates-in-c-why-are-inherited-members-invisible

template &lt;typename T&gt;
struct variant2 : public std::variant&lt;std::monostate, int, T&gt; 
{
    using inner_variant_type = typename variant2::variant;
    //                         ^^^^^^^^ ---&gt; required 

    // required to mention, that the operator= is from the parent !!
    using std::variant&lt;std::monostate, int, T&gt;::operator=;  

    template &lt;variant_type&lt;inner_variant_type&gt; U&gt;
    auto assign(const U&amp; var) {
        *this = var;
    }
};

See a demo

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

发表评论

匿名网友

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

确定