【问题标题】:How to extract requires clause with two parameter packs into a concept?如何将带有两个参数包的 requires 子句提取到一个概念中?
【发布时间】:2021-12-26 04:33:11
【问题描述】:

我有这个(据说不是那么有用)类模板,它带有模板化构造函数,它是完美转发的候选者。但是,我想确保传递给构造函数的类型与为整个类指定的类型完全相同(没有 cvref 限定符):

template <typename... Ts>
struct foo {
    template <typename... CTs>
    requires (std::same_as<std::remove_cvref_t<Ts>, std::remove_cvref_t<CTs>> && ...)
    foo(CTs&& ...) {
        std::cout << "called with " << (sizeof...(CTs)) << " args\n";
    }
};

现在我可以制作了:

auto f = foo<int, int>(1, 1);

我做不到:

auto f = foo<float, int>(1, 1);

这很好。


但我想将requires ... 正文提取到concept

template <typename... T1s, typename... T2s>
concept same_unqualified_types = (
        std::same_as<
                std::remove_cvref_t<T1s>,
                std::remove_cvref_t<T2s>
        > && ...
);

template <typename... Ts>
struct foo {
    template <typename... CTs>
    requires same_unqualified_types<Ts..., CTs...>
    foo(CTs&& ...) {                // 16
        std::cout << "called with " << (sizeof...(CTs)) << " args\n";
    }
};

int main() {
    auto f = foo<int, int>(1, 1);   // 22
}

但这给了我这个错误:

main.cpp: In function 'int main()': 
main.cpp:22:32: error: no matching function for call to 'foo<int, int>::foo(int, int)'
22 |     auto f = foo<int, int>(1, 1);
   |   
main.cpp:16:5: note: candidate: 'template<class ... CTs>  requires  same_unqualified_types<Ts ..., CTs ...> foo<Ts>::foo(CTs&& ...) [with CTs = {CTs ...}; Ts = {int, int}]'
16 |     foo(CTs&& ...) {
   |     ^~~
main.cpp:16:5: note:   template argument deduction/substitution failed:
main.cpp:16:5: note: constraints not satisfied
main.cpp: In substitution of 'template<class ... CTs>  requires  same_unqualified_types<Ts ..., CTs ...> foo<int, int>::foo(CTs&& ...) [with CTs = {int, int}]':
main.cpp:22:32:   required from here
main.cpp:5:9:   required for the satisfaction of 'same_unqualified_types<Ts ..., CTs ...>' [with CTs = {int, int}; Ts = {int, int}]
main.cpp:22:32: error: mismatched argument pack lengths while expanding 'same_as<typename std::remove_cvref<T1s>::type, typename std::remove_cvref<T2s>::type>'
22 |     auto f = foo<int, int>(1, 1);
   |    

我想我可能对concept same_unqualified_types 做错了,我试图有两个参数包。我尝试手动测试它,但它似乎不起作用,即使我执行same_unqualified_types&lt;int, int&gt;same_unqualified_types&lt;int, int, Pack...&gt;,其中Pack... 是两个ints 的参数包。

我的逻辑哪里有缺陷?我可以将requires 子句提取到concept 吗?

免责声明:我知道我可以通过 CTAD 和演绎指南实现类似的目标 - 甚至不需要任何概念。我只是想知道我的理解哪里有缺陷。

【问题讨论】:

    标签: c++ c++20 c++-concepts template-argument-deduction parameter-pack


    【解决方案1】:

    概念在模板参数包方面没有特殊权限。一组模板参数中不能有两个包,除非根据传递给它们的参数可以区分它们(一个可能是一系列类型,另一个是一系列值,或者您可以访问模板论据推论以区分它们,或类似的东西)。

    您能做的最好的事情是创建一个不合格的 same_as 等效项,并根据需要将其与包扩展一起使用:

    
    template<typename T, typename U>
    concept same_as_unqual = std::same_as<<std::remove_cvref_t<T>, <std::remove_cvref_t<U>>;
    
    template <typename... Ts>
    struct foo {
        template <typename... CTs>
        requires (same_as_unqual<Ts, CTs> && ...)
        ...
    

    在参数之间进行成对比较的单个概念是不可能的。嗯,这是可能的,但它会更加冗长,因为您可能需要将它们捆绑在某种类型列表中。我不认为same_as_all&lt;type_list&lt;Ts...&gt;, type_list&lt;Us...&gt;&gt; 比进行显式扩展更好。

    【讨论】:

      猜你喜欢
      • 2021-12-30
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-15
      相关资源
      最近更新 更多