标签: c++-concepts

有关AFT(缩写功能模板)的争议是什么?

为什么这个功能看起来如此有争议?我看到它没有与其他概念TS一起合并到C++ 20中.通过网络搜索,除了可以应用于几乎任何新的C++特性的通用参数之外,我找不到合理的参数.

人们如此害怕什么?那里有什么陷阱?毕竟,我们已经有了通用的lambda.

c++ c++-concepts c++20

8
推荐指数
1
解决办法
276
查看次数

C++ 概念 - 我可以有一个要求在类中存在函数的约束吗?

我在下面有一个简单的代码片段,它使用以下编译:

g++-9 -std=c++2a -fconcepts

这是试图定义一个需要函数存在的概念。我希望输出是“是”,但它不是......知道为什么吗?谢谢。

#include <iostream>


template <typename T>
concept bool HasFunc1 = 
    requires(T) {
        { T::func1() } -> int;
    };

struct Test
{
    int func1()
    {
        return 5;
    }
};

int main()
{
    if constexpr (HasFunc1<Test>)
        std::cout << "yes\n";
}
Run Code Online (Sandbox Code Playgroud)

c++ template-meta-programming c++-concepts

8
推荐指数
3
解决办法
2673
查看次数

使用基于概念的递归函数模板在推导“auto”之前使用“auto [...]”

我想创建一个deep_flatten函数模板,它会产生一个range深度join编辑的元素。例如,如果我们只考虑嵌套的std::vectors,我可以有:

template <typename T>
struct is_vector : public std::false_type { };

template <typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type { };

template <typename T>
auto deepFlatten(const std::vector<std::vector<T>>& vec) {
    using namespace std::ranges;
    if constexpr (is_vector<T>::value) {
        auto range = vec | views::join;
        return deepFlatten(std::vector(range.begin(), range.end()));
    } else {
        auto range = vec | views::join;
        return std::vector(range.begin(), range.end());
    }
}
Run Code Online (Sandbox Code Playgroud)

这使我能够做到:

std::vector<std::vector<std::vector<int>>> nested_vectors = {
        {{1, 2, 3}, {4, 5}, …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts c++20 std-ranges

8
推荐指数
1
解决办法
531
查看次数

如何在约束中使用 ADL?

例如,我想使用约束来确保isinf为模板参数实现该函数T。如果T是一floatdoublelong double或一体式,这可以通过以下方式进行:

#include <cmath>

template <typename T>
concept Test = requires (T a) {
    std::isinf(a);
};
Run Code Online (Sandbox Code Playgroud)

但是,我也想将此约束用于我实现自己的isinf函数的自定义非标准数据类型。这个函数不包含在std命名空间中,所以我尝试了以下方法:

#include <cmath>

template <typename T>
concept Test = requires (T a) {
    using std::isinf;
    isinf(a);
};
Run Code Online (Sandbox Code Playgroud)

这是行不通的,因为 requires 子句中的每个语句都应该是有效的要求,而using std::isinf根本不是“要求”。

我看到了这个问题的两种解决方法:

  • using std::isinf;子句移动到全局命名空间。但这引入isinf了我想避免的全局命名空间。

  • using std::isinf;带有概念定义的子句封装在名为 的命名空间中ABC,然后using ABC::Test;直接添加到命名空间之后。这似乎有点奇怪。

有更好的解决方案吗?

c++ argument-dependent-lookup c++-concepts c++20

8
推荐指数
1
解决办法
136
查看次数

如何要求约束中存在函数?

我有一个vector.h带有自定义Vector类的文件,其中向量条目的数据类型应限制f为实现函数的类型:

template <typename T>
concept Vector_Type = requires (T a) {
    f(a);
};

template <Vector_Type T>
class Vector {};
Run Code Online (Sandbox Code Playgroud)

此外,我有多个文件,其中f为不同的数据类型定义了函数,例如以下datatype_int.h头文件:

int f(int a) { return 2*a; }
Run Code Online (Sandbox Code Playgroud)

如果我包含datatype_int.hafter vector.h,编译器会抱怨不满足约束:

#include "vector.h"
#include "datatype_int.h"

int main() {
    Vector<int> v;  // Error: constraints not satisfied

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这不是一个非常有用的错误消息,我想避免依赖于包含的顺序。但是,没有办法来声明函数f的所有可能的数据类型Tvector.h,因为我不知道哪个数据类型将被用来做。

我怎么解决这个问题?

c++ c++-concepts c++20

8
推荐指数
1
解决办法
127
查看次数

用概念重载函数

(我正在学习概念和模板,所以如果我有什么不对的地方,请纠正我。)我有一个将概念作为参数的函数。我现在试图重载这个需要更具体概念的函数。那会做“更具体的事情”或调用不太具体的功能。

template<typename T>
concept Concept1 = ...;

template<typename T>
concept MoreSpecificConcept = ...;
    Concept1 <T> &&
    ...;

//...
void someFunc(const Concept1 auto& x)
{
  //do general stuff
}

void someFunc(const MoreSpecificConcept auto& x)
{
  if(...)
  {
    //do specific stuff
  }
  else
  {
    //do the more general thing:

    // Problem. Trying to call itself:
    someFunc(x);
  }
}
Run Code Online (Sandbox Code Playgroud)

有什么方法可以明确告诉编译器要调用哪个重载(例如someFunc<Concept1>(x)哪个不起作用),还是仅依赖于传递对象的类型?可以说我不能x转换为更通用的类型,并且更通用的函数/概念不知道这个更具体的函数/概念,所以他们不能用约束排除它。编辑:这些函数应该在同一个(全局)命名空间内。

c++ templates overloading c++-concepts c++20

8
推荐指数
1
解决办法
204
查看次数

为什么 `constexpr` 函数可以在编译和运行时产生不同的结果?

我的一位同事向我展示了这个令人震惊的 C++20 程序:

#include <iostream>

constexpr int p(auto) { return 0; }
constexpr int q() { return p(0); }
constexpr int p(auto) requires true { return 1; }

static_assert(p(0) == 1);
static_assert(q() == 0);

int main()
{
    std::cout << q() << p(0) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

由于错误,GCC 无法构建它:

Error: symbol `_Z1pIiEiT_' is already defined
Run Code Online (Sandbox Code Playgroud)

Clang 成功构建程序并打印11https://gcc.godbolt.org/z/1Gf5vj5oo)。所以static_assert(q() == 0)被成功检查,但std::cout << q()仍然打印1. 怎么会这样?

Visual Studio 2019 16.10.4 的行为更加怪异。在 Release 配置中它也打印11,在 Debug …

c++ language-lawyer constexpr c++-concepts c++20

8
推荐指数
1
解决办法
170
查看次数

标准库中是否有一个概念可以测试范围 for 循环的可用性

有许多不同的方法可以使类型/类在范围 for 循环中可用。例如,在cppreference上给出了概述:

range-expression进行评估以确定要迭代的顺序或范围。序列中的每个元素依次被取消引用,并用于使用范围声明中给定的类型和名称来初始化变量。

begin_exprend_expr定义如下:

  • 如果range-expression是数组类型的表达式,则begin_expris__rangeend_expris ( __range+ __bound),其中__bound是数组中元素的数量(如果数组大小未知或类型不完整,则程序格式错误)
  • 如果是同时具有指定成员和指定成员的range-expression类类型的表达式(无论该成员的类型或可访问性如何),则is且isCbeginendbegin_expr__range.begin()end_expr__range.end()
  • 否则,begin_exprisbegin(__range)end_expris end(__range),它们是通过参数相关的查找找到的(不执行非 ADL 查找)。

如果我想在函数模板中使用范围 for 循环,我想限制类型在范围 for 循环中可用,以触发编译器错误并显示一条漂亮的“约束不满足”消息。考虑以下示例:

template<typename T>
requires requires (T arg) {
  // what to write here ??
}
void f(T arg) {
    for ( auto e : arg ) {
    } …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts ranged-loops c++20

8
推荐指数
1
解决办法
238
查看次数

约束表达式无效

与 GCC 12.2 和 MSVC 19.33 相比,以下代码示例不能使用 Clang 15 或 Clang trunk 进行编译。嵌套required子句中的约束表达式是否无效?

struct t {
    constexpr auto b() const noexcept
    { return true; }
};

template<typename T>
concept c = requires(T t) {
    requires t.b();
};

static_assert(c<t>);
Run Code Online (Sandbox Code Playgroud)

Clang 产生的错误消息:

<source>:11:1: error: static assertion failed
static_assert(c<t>);
^             ~~~~
<source>:11:15: note: because 't' does not satisfy 'c'
static_assert(c<t>);
              ^
<source>:8:14: note: because 't.b()' would be invalid: constraint variable 't'
cannot be used in an evaluated context
    requires t.b();
             ^ …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts c++20

8
推荐指数
1
解决办法
422
查看次数

如何在需求表达式中重用函数调用的返回类型?

我正在编写一个概念,检查类型是否可以在组成 2 个函数的表达式中使用:

template<typename T>
concept C = requires(T t) {
    f(g(t));
};
Run Code Online (Sandbox Code Playgroud)

即,我想检查对于给定的t类型 的对象T,我是否可以调用g(t),然后使用结果值作为 的参数f。例如,

auto g(int)  -> float;   
auto g(char) -> double; 

void f(float);
void f(double) = delete;

static_assert(C<int>);       // g(int) returns a float, so f(float) is called.
static_assert(not C<char>);  // g(char) returns a double, but f(double) is deleted
Run Code Online (Sandbox Code Playgroud)

这很好用。

但是,我想拆分对fand的调用g,因为 1)g可能需要额外的参数(不依赖于),从而导致冗长T的调用,2) 我可能想在g概念,所以我不想多次重复调用。

像下面这样的天真尝试

auto res = g(t);
f(res);
Run Code Online (Sandbox Code Playgroud)

和 …

c++ templates c++-concepts requires-expression

8
推荐指数
1
解决办法
372
查看次数