提问者:小点点

C++20中变量函数中的多个概念约束参数包不接受第一个参数包中的参数


下面的代码使用多个参数包定义一个可变模板累加器函数,该函数接受任何数值类型或指向数值类型的指针:

// Compile with --std=c++20

#include <type_traits>

template <typename T>
concept number = std::is_arithmetic_v<T>
             && !std::is_pointer_v<T>;

template <typename T>
concept pointer = std::is_arithmetic_v<std::remove_pointer_t<T>>
               && std::is_pointer_v<T>;


double foo ()
{return 0;}

double foo (pointer auto     p0)
{return *p0;}

double foo (pointer auto     p0,
            pointer auto ... ps)
{return *p0 + foo (ps ...);}

double foo (number  auto     n0,
            pointer auto ... ps)
{return n0 + foo (ps ...);}

double foo (number  auto     n0,
            number  auto ... ns,
            pointer auto ... ps)
{return n0 + foo (ns ..., ps ...);}


int main()
{
    float f = 3.;
    unsigned u = 4;
    
    foo (); // Compiles
    foo (1); // Compiles
    foo (&f); // Compiles
    foo (1, &f); // Compiles
    foo (1, &f, &u); // Compiles
    foo (&f, &u); // Compiles
    
    foo (1, 2.); // Error!
    foo (1, 2., &f); // Error!
    foo (1, 2., &f, &u); // Error!
}

当存在多个number类型的参数时,会触发错误。

看起来像是当存在多个参数包时,编译器将所有参数打包在最后一个包中,而不是引用约束来定义哪个参数包属于哪个参数包。

这是语言的限制吗? 多个参数包是否意味着以某种其他方式使用? 有没有什么变通办法让它发挥作用?

在clang和GCC中测试过


共1个答案

匿名用户

函数参数包的扣减仅发生在参数列表中的最后一个包。 所有其他包都被认为是非推导上下文:

未推导的上下文为:

。。。

不出现在参数声明列表末尾的函数参数包。

概念不影响这一点。 你不能使用概念作为一种方法,使第一个包是可推论的。

在任何情况下,只要有一个算术类型或指向算术类型的指针的概念,一个折叠表达式和一个用来区分哪个和哪个的函数,就会容易得多:

#include <type_traits>

template <typename T>
concept number = std::is_arithmetic_v<T>; //Pointers aren't arithmetic types.

template <typename T>
concept ptr_to_num =
    std::is_pointer_v<T> &&
    number<std::remove_pointer_t<T>>;

template<typename T>
concept ptr_to_num_or_num =
    number<T> || ptr_to_num<T>;

template<ptr_to_num_or_num T>
double dereference(T p)
{
    if constexpr(ptr_to_num<T>)
        return *p;
    else
        return p;
}

template<ptr_to_num_or_num ...Args>
double foo(Args ...args)
{
    return (0.0 + ... + dereference(args));
}

int main()
{
    float f = 3.;
    unsigned u = 4;
    
    foo (); // Compiles
    foo (1); // Compiles
    foo (&f); // Compiles
    foo (1, &f); // Compiles
    foo (1, &f, &u); // Compiles
    foo (&f, &u); // Compiles
    
    foo (1, 2.); // Error!
    foo (1, 2., &f); // Error!
    foo (1, 2., &f, &u); // Error!
}

是的,您将能够在数字之前传递指针。 但这不是一个更好的界面,无论你想做什么吗?

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(c++20|中|变量|函数|中|多个|概念|约束|参数|包|不接受|第一个|参数|包|中|参数)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?