您可能已经听说过,C++标准委员会的最后一次会议投票决定从下一个C++标准中删除概念.当然,这会影响其他功能,并且似乎再次打开标准.如果是这种情况,您认为哪些其他功能应该被删除(或添加),为什么?
链接:
删除概念 - Danny Kalev(关于删除概念的决定)
简化概念的使用 - Bjarne Stroustrup(关于现在看来的概念问题)
长杆变得更长 - 马丁Tasker(如果必须修复概念,对C++ 0x的时间表的影响)
关于Dobbs博士问题的C++ 0x"删除概念"决定 - Stroustrup
旅行报告:退出概念,约18个月的最终ISO C++草案 - Herb Sutter
概念获得投票C++ 0x岛 - Jeremy Siek捍卫当前的概念规范
法兰克福发生了什么? - Doug Gregor关于C++ Next(关于概念的历史和删除).
在回答关于CodeReview的这个问题时,我在思考如何编写模板函数来指示const包含对象的内容.
具体而言,请考虑这个模板化函数
#include <iostream>
#include <numeric>
#include <vector>
template <class It>
typename std::iterator_traits<It>::value_type average(It begin, It end) {
typedef typename std::iterator_traits<It>::value_type real;
real sum = real();
unsigned count = 0;
for ( ; begin != end; ++begin, ++count)
sum += *begin;
return sum/count;
}
int main()
{
std::vector<double> v(1000);
std::iota(v.begin(), v.end(), 42);
double avg = average(v.cbegin(), v.cend());
std::cout << "avg = " << avg << '\n';
}
Run Code Online (Sandbox Code Playgroud)
它需要一个迭代器并根据包含的数字计算平均值,但保证不通过传递的迭代器修改向量.如何将此传达给模板的用户?
请注意,声明如下:
template <class It>
typename std::iterator_traits<It>::value_type average(const It …Run Code Online (Sandbox Code Playgroud) 考虑这个例子:
template <typename T> inline constexpr bool C1 = true;
template <typename T> inline constexpr bool C2 = true;
template <typename T> requires C1<T> && C2<T>
constexpr int foo() { return 0; }
template <typename T> requires C1<T>
constexpr int foo() { return 1; }
constexpr int bar() {
return foo<int>();
}
Run Code Online (Sandbox Code Playgroud)
调用是foo<int>()不明确的,还是约束C1<T> && C2<T>包含C1<T>?
我查看了 clang-format 样式选项https://clang.llvm.org/docs/ClangFormatStyleOptions.html但没有看到任何对 c++ 概念和需要子句的引用。通常我可以配置 clang-format 来做我想做的事,但我不知道如何让它很好地处理我的概念和需要条款:
template <typename F, typename P, typename T>
concept Accumulate_Fn = Parser<P>&& std::invocable<F, T, parser_t<P>>&&
std::same_as<T, std::invoke_result_t<F, T, parser_t<P>>>;
Run Code Online (Sandbox Code Playgroud)
但是我想将每个约束放在自己的行上(就像它处理太长的函数参数一样),以便结果如下所示:
template <typename F, typename P, typename T>
concept Accumulate_Fn = Parser<P> &&
std::invocable<F, T, parser_t<P>> &&
std::same_as<T, std::invoke_result_t<F, T, parser_t<P>>>;
Run Code Online (Sandbox Code Playgroud)
template <Parser P1, Parser P2, typename T, Accumulate_Fn<P1, parser_t<P1>> F>
requires std::same_as<T, parser_t<P1>> constexpr Parser auto
separated_by(P1&& p1, P2&& p2, T&& init, F&& f)
Run Code Online (Sandbox Code Playgroud)
但我想要更接近的东西: …
我已经滚动并搜索了标准和cppreference几个小时但无济于事,如果有人能为我解释这种情况,我将不胜感激:
我在看标准概念std::convertibe_to。这是我理解的一个简单示例
class A {};
class B : public A {};
std::convertible_to<A, B>; // false
std::convertible_to<B, A>; // true
Run Code Online (Sandbox Code Playgroud)
按预期工作。
现在还有另一种可能的使用方式,我不太明白
void foo(std::convertible_to<A> auto x) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
,并且这个函数可以很容易地接受任何可转换为 A 的类型。但这很奇怪,因为第一个模板参数(“From”)本质上被删除了,并在函数调用时推导出来。下面的这个函数也可以工作,我很确定它实际上等同于前一个
template<typename T, std::convertible_to<T> S>
void foo(S x) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
x当我们调用 时,再次推导出的类型foo。
尽管模板需要两个参数,但这仍然有效。我也尝试过std::derived_from,它似乎有效。这种仅用一个模板参数指定概念的形式甚至出现在标准本身中,因此必须有一些语法来解释它。
请注意,只有版本的std::convertible_to存在,其实是一个有两个模板参数。
任何人都可以澄清为什么这有效?
C++20 中的约束在通过将它们划分为原子约束来检查是否满足之前进行标准化。例如,约束E = E1 || E2有两个原子约束E1和E2
原子约束中的替换失败应被视为原子约束的假值。
如果我们考虑一个示例程序,则会concept Complete = sizeof(T)>0检查正在定义的类T:
template<class T>
concept Complete = sizeof(T)>0;
template<class T, class U>
void f() requires(Complete<T> || Complete<U>) {}
template<class T, class U>
void g() requires(sizeof(T)>0 || sizeof(U)>0) {}
int main() {
f<void,int>(); //ok everywhere
g<void,int>(); //error in Clang
}
Run Code Online (Sandbox Code Playgroud)
那么该函数f<void,int>()满足要求,因为由于替换失败而Complete<void>计算为,并且计算为。falseComplete<int>true
但相似的函数g<void,int>()会使编译器产生分歧。GCC 接受它,但 Clang 不接受:
error: no matching function for call to 'g'
note: …Run Code Online (Sandbox Code Playgroud) 我正在尝试移植一个库以在 MSVC 上进行编译。该库将数据存储在向量元组 ( std::tuple<std::vector<Ts>...>) 中,并使用自定义迭代器同时迭代所有向量(类似于 zip_iterator 的作用)。
迭代器定义的类型如下所示(假设Ts...-> <int, int>):
`value_type` is `std::tuple<int, int>`
`reference` is `std::tuple<int&, int&>`
Run Code Online (Sandbox Code Playgroud)
问题是,在最新的 MSVC (v. 19.35) 上,这个迭代器不满足 的概念std::input_iterator,而在 gcc/clang 上却满足它。
经过进一步调查,我发现失败是由于std::common_reference元组上的概念行为不一致造成的。
以下static_assert内容在 MSVC 上失败,而在 gcc/clang 上不会失败
using T = std::tuple<int, int>&;
using U = std::tuple<int&, int&>;
static_assert(std::common_reference_with<T, U>, "failed common_reference_with");
Run Code Online (Sandbox Code Playgroud)
这是Godbolt上的(还有一个迭代器示例)
像这样的类型std::tuple<int, int>&应该有一个“ common_reference_with”std::tuple<int&, int&>吗?MSVC 说不,gcc 说可以。
根据 C++20 及以后的标准,这两种行为中的哪一种是预期的?
有没有什么简单的方法可以使这个迭代器成功通过 MSVC 上的迭代器概念检查(即强制这两种类型具有共同的引用)? …
在注视GCC 4.9.0版本改变了这里,我惊喜地阅读以下; 在C++的"新语言和语言特定改进"部分下:
G ++支持N3889的§4.1.2和§5.1.1:Concepts Lite Specification所规定的无约束泛型函数.简而言之,auto可以用作任何函数声明符的参数声明中的类型说明符,以便引入隐式函数模板参数,类似于通用lambdas.
// the following two function declarations are equivalent
auto incr(auto x) { return x++; }
template <typename T>
auto incr(T x) { return x++; }
Run Code Online (Sandbox Code Playgroud)
我构建了GCC 4.9.0,我的初始测试按预期工作.我相信Concepts Lite将继续以某种方式辅助即将推出的C++ 14规范.是否有任何"无约束通用函数"计划成为C++的一部分?
考虑以下课程:
struct C
{
/* Class contents, without any arithmetic operator... */
constexpr operator int() noexcept; // Implicit conversion to int
};
Run Code Online (Sandbox Code Playgroud)
我的问题是:
std::sort当前使用默认<运算符的标准算法?LessThanComparable概念吗?LessThanComparable.概念未实例化([temp.spec]).[注意:表示概念特化的id表达式被计算为表达式([expr.prim.id]).[...]
这是否意味着此规则([temp.point]/8)不适用?
如果两个不同的实例化点根据单定义规则给出模板特化的不同含义,则程序形成错误,不需要诊断.
例如,如果此规则不适用,则以下代码形式良好:
template<class T>
concept Complete = sizeof(T)==sizeof(T);
struct A;
constexpr inline bool b1 = Complete<A>; //Complete<A>==false;
struct A{};
constexpr inline bool b2 = Complete<A>; //Complete<A>==true;
Run Code Online (Sandbox Code Playgroud)
这个问题是后面这一个
c++-concepts ×10
c++ ×9
c++20 ×5
c++11 ×2
templates ×2
auto ×1
c++14 ×1
c++17 ×1
clang-format ×1
constraints ×1
generics ×1
std ×1
tuples ×1