【问题标题】:How do I define this C++ constraint?如何定义这个 C++ 约束?
【发布时间】:2021-07-05 19:14:18
【问题描述】:

我有两种类型AA_InputAA_Input 构造而成。

我想定义一个模板类B,它有两个模板参数TU。然后我想为B 定义一个约束,要求T 有一个接受U 的构造函数。

我写这样一个B 的尝试如下:

template<typename T, typename U>
requires requires (U u) {
    T::T(u);
}
class B {
public:
    B(){}
    void speak() {
        std::cout << "success!";
    }
};

一个例子Tclass A 并且隐含的UA_Inputs 下面提供:

class A_Inputs {
public:
    A_Inputs(){}
};

class A {
public:
    A(A_Inputs ain){}
};

然后我使用以下 main 函数测试所有内容:

int main() {
    B<A, A_Inputs> b{};
    b.speak();
    return 0;
}

这会给

error C7602: 'B': the associated constraints are not satisfied

【问题讨论】:

    标签: c++ templates constraints c++20 c++-concepts


    【解决方案1】:

    可构造性约束的写法是使用constructible_from概念:

    template<typename T, typename U>
        requires std::constructible_from<T, U>
    class B { ... };
    

    【讨论】:

    • 我以为我浏览了所有的 cppreference 概念。我没有注意到顶部的下拉菜单。
    【解决方案2】:

    您应该阅读整个错误消息,而不仅仅是其中的一行。

    With gcc I get:

    <source>: In function 'int main()':
    <source>:31:18: error: template constraint failure for 'template<class T, class U>  requires requires(U u) {(T::T)(u);} class B'
       31 |     B<A, A_Inputs> b{};
          |                  ^
    <source>:31:18: note: constraints not satisfied
    <source>: In substitution of 'template<class T, class U>  requires requires(U u) {(T::T)(u);} class B [with T = A; U = A_Inputs]':
    <source>:31:18:   required from here
    <source>:7:7:   required by the constraints of 'template<class T, class U>  requires requires(U u) {(T::T)(u);} class B'
    <source>:4:10:   in requirements with 'U u' [with T = A; U = A_Inputs]
    <source>:5:9: note: the required expression 'T::T(u)' is invalid
        5 |     T::T(u);
          |     ~~~~^~~
    cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
    [...]
    

    还有更多关于其他错误的信息,这些错误只是由于B&lt;A, A_Inputs&gt; b{}; 不正确造成的。这里的重要部分是'T::T(u)' 无效。应该是T(u);:

    #include <iostream>
    
    template<typename T, typename U>
    requires requires (U u) {
        T(u);
    }
    class B {
    public:
        B(){}
        void speak() {
            std::cout << "success!";
        }
    };
    
    class A_Inputs {
    public:
        A_Inputs(){}
    };
    
    class A {
    public:
        A(A_Inputs ain){}
    };
    
    class X {
        public:
        X() {}
    };
    
    int main() {
        B<A, A_Inputs> b{};
        b.speak();
        B<X, A_Inputs> x{};
    }
    

    这只会像预期的那样对 B&lt;X, A_Inputs&gt; x{}; 产生错误,因为没有满足约束。

    【讨论】:

      【解决方案3】:
      template<class Src, class Dest>
      concept can_construct  = requires(Src s){
        { Dest(std::forward<Src>(s)); }
      }
      
      template<typename T, can_construct<T> U>
      class B
      

      喜欢吗?

      您应该寻求使用命名概念。这还允许您添加它们的静态断言测试,以在更简单的上下文中捕获错误。

      请注意,can_construct&lt;T&gt; U 需要 can_construct&lt;U,T&gt; - U 是“前缀”到概念模板参数中。

      【讨论】:

        猜你喜欢
        • 2015-02-04
        • 2022-10-07
        • 2018-11-18
        • 2020-04-21
        • 2011-11-01
        • 2018-06-17
        • 2019-09-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多