升级到最新的 Visual Studio 2022 版本 17.6 后,我们的自定义视图之一停止被识别为std::ranges::range. 事实证明,问题出在视图的迭代器中operator ==。operator !=
请找到下面的最小简化示例(已经没有视图和迭代器):
struct A {
friend bool operator ==( const A &, const A & ) = default;
};
struct B {
friend bool operator ==( const B &, const B & ) = default;
friend bool operator ==( const B &, const A & ) { return false; }
// Visual Studio 2022 version 17.6 does not like next line
friend bool operator !=( const …Run Code Online (Sandbox Code Playgroud) 根据en.cppreference.com(据我所知):
std::is_convertible被性状类需要类型From&To为使得与返回类型的函数To返回一个From值可以通过编译。std::convertible_to是一个概念,要求类型From&To如上所述,AND使得类型的r 值引用From可以转换为static_cast<To>。强加的要求std::is_convertible似乎相对简单。相反,对于 C++20 特性的简单示例中显示的这种通用概念,r 值引用转换要求std::convertible_to似乎奇怪地特定。
作为 C++ 的新手,我无法完全理解两个网页中提供的一些术语和部分补充说明,我无法想象两者的要求之间的确切区别。
一些相互关联的问题:
From& Toof 不仅受到std::is_convertible奇怪的 r 值引用转换要求的约束,而且受到奇怪的 r 值引用转换要求的实际影响是什么?From和To被附加由R值参考铸件的要求被拒绝?std::is_convertible或std::convertible_to中的一个而不是另一个作为其函数返回类型或参数类型的约束(除了概念的便利性)?一个更简单的解释或一个例子会有所帮助。谢谢!
最近,来自Concepts TS的C++概念已合并到GCC主干中.概念允许人们通过要求类型来满足概念的条件(例如"可比较")来约束通用代码.
Haskell有类型类.我对Haskell并不熟悉.概念和类型类是如何相关的?
考虑函数模板的以下两个重载foo:
template <typename T>
void foo(T) requires std::integral<T> {
std::cout << "foo requires integral\n";
}
template <typename T>
int foo(T) requires std::integral<T> && true {
std::cout << "foo requires integral and true\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意两个约束之间的区别:第二个约束有一个额外的&& true.
直观地说,true在连词中是多余的(因为X && trueis just X)。然而,它看起来像这使得语义差别,如foo(42)将调用第二个过载。
为什么会这样?具体来说,为什么第二个函数模板是更好的重载?
如何使用概念if constexpr?
给出下面的例子,if constexpr如果T满足要求,则返回1 将给予integral什么?
template<typename T>
concept integral = std::is_integral_v<T>;
struct X{};
template<typename T>
constexpr auto a () {
if constexpr (/* T is integral */) {
return 1;
}
else {
return 0;
}
}
int main () {
return a<X>();
}
Run Code Online (Sandbox Code Playgroud) 适用于类的语法不适用于概念:
template <class Type>
concept C = requires(Type t) {
// ...
};
template <class Type>
concept C<Type*> = requires(Type t) {
// ...
};
Run Code Online (Sandbox Code Playgroud)
MSVC 对于“专业化”行的说法是:error C7606: 'C': concept cannot be explicitly instantiated, explicitly specialized or partially specialized。
为什么概念不能专门化?有理论上的原因吗?
在此代码中,
template<class T, class U>
concept always_true = true;
template<class T>
concept always_true_if_tagged = always_true<T, typename T::tag>;
struct A {
using tag = int;
};
static_assert(always_true_if_tagged<A>);
static_assert(!always_true_if_tagged<int>); //GCC says this failed
Run Code Online (Sandbox Code Playgroud)
GCC 表示第二个断言失败。Clang 和 MSVC 都同意编译它。
我最初认为它是不正确的,不需要诊断,因为temp.constr.normal#1.4
概念 ID 的范式
C<A1, A2, ..., An>是 的约束表达式的范式C,在替换A1, A2, ..., An每个C原子约束中的参数映射中的各自模板参数后。如果任何此类替换导致无效类型或表达式,则该程序格式错误;无需诊断。
替换T::typename tag是 的参数映射always_true,因此格式错误;无需诊断。
所以我的前两个问题是
解决方案之一是检查之前的嵌套类型名。所以参数映射always_true不会发生。
template<class T>
concept always_true_if_tagged =
requires …Run Code Online (Sandbox Code Playgroud) 我想测试一个类型是否可以传递给某个函数,但我想在函数查找上使用 ADL 并包含来自某个命名空间的函数。
考虑这段代码:
#include <utility>
#include <vector>
template<class T>
concept Swappable = requires(T& a, T& b)
{
swap(a,b);
};
static_assert(Swappable<std::vector<int>>); // #1
static_assert(Swappable<int>); // #2
Run Code Online (Sandbox Code Playgroud)
#1 成功,它发现std::swapbecausestd是 的关联命名空间std::vector<int>。但 #2 失败了,内置类型没有关联的命名空间。
我该怎么写这样的东西:
template<class T>
concept Swappable = requires(T& a, T& b)
{
using std::swap; // illegal
swap(a,b);
};
Run Code Online (Sandbox Code Playgroud)
AFAIK,您不允许在 require 表达式中使用 using 声明。
(注意,虽然对此有一个完美的标准 C++ 概念,但std::swappable此示例swap仅用于说明。我并不是特别想测试某些东西是否实际上是可交换的,我只是想找到一种方法来实现这样的概念其中自定义函数在已知命名空间中具有默认实现,但可能在关联的命名空间中具有重载。)
编辑作为一种解决方法,我可以在一个单独的名称空间中实现这个概念,其中的名称被拉入。对此不太满意,但它有效。
namespace detail
{
using std::swap;
template<class T>
concept Swappable = …Run Code Online (Sandbox Code Playgroud) 假设我有一个这样的简单模板:
template<typename T>
class A {};
Run Code Online (Sandbox Code Playgroud)
我想指定type-parameter T属于某种不相关的类型X<U>,其中U不知道(或不可指定).
有没有办法如何表达这个概念?
鉴于:
#include <concepts>
#include <iostream>
template<class T>
struct wrapper;
template<std::signed_integral T>
struct wrapper<T>
{
wrapper() = default;
void print()
{
std::cout << "signed_integral" << std::endl;
}
};
template<std::integral T>
struct wrapper<T>
{
wrapper() = default;
void print()
{
std::cout << "integral" << std::endl;
}
};
int main()
{
wrapper<int> w;
w.print(); // Output : signed_integral
return 0;
}
Run Code Online (Sandbox Code Playgroud)
从上面的代码中,int符合std::integral和std::signed_integral概念。
令人惊讶的是,这会在 GCC 和 MSVC 编译器上编译并打印“signed_integral”。我原以为它会失败,并出现“模板专业化已经定义”的错误。
好的,这是合法的,足够公平,但为什么std::signed_integral选择而不是std::integral?当多个概念符合模板参数的条件时,标准中是否定义了任何规则来选择模板特化?