不允许这样约束一个概念:
template<typename T>
concept A = expr_1;
template<A T>
concept B = expr_2; // error
Run Code Online (Sandbox Code Playgroud)
然而,似乎总是可以达到相同的结果,如下所示:
template<typename T>
concept A = expr_1;
template<typename T>
concept B = A<T> && expr_2; // ok
Run Code Online (Sandbox Code Playgroud)
如果第一个版本总是可以重写为第二个版本,那么为什么不允许第一个版本呢?
在 C++20 中,我们现在可以使用概念而不是 SFINAE 来确定模板类型名中是否存在函数:
template<typename T> concept fooable = requires (T a) {
a.foo();
};
class Foo {
public:
// If commented out, will fail compilation.
void foo() {}
void bar() {}
};
template <typename T> requires fooable<T>
void foo_it(T t) {
t.bar();
}
int main()
{
foo_it(Foo());
}
Run Code Online (Sandbox Code Playgroud)
我们如何使用具有非空参数的函数来做到这一点?
如何编写检测指向算术类型的指针的概念?
template <typename T>
concept arithmetic = std::is_arithmetic<T>::value;
template <typename T>
concept pointer_to_arithmetic = requires (T a) {
{ *a } -> arithmetic;
};
template <typename T>
void fn() {
printf("fail\n");
}
template <pointer_to_arithmetic T>
void fn() {
printf("pass\n");
}
struct s{};
int main() {
fn<int>();
fn<int*>();
fn<s>();
fn<s*>();
}
Run Code Online (Sandbox Code Playgroud)
我试过上面的,它编译但没有做它应该做的。
预期输出为:
fail
pass
fail
fail
Run Code Online (Sandbox Code Playgroud)
相反,我得到:
fail
fail
fail
fail
Run Code Online (Sandbox Code Playgroud)
如果我替换*a为a[0].
对于具有许多大型和复杂模板实例的库,在我看来,决定是否使用概念的主要考虑因素之一是构建输出的大小是否更小。
使用 SFINAE,我的理解是以下代码将导致模板实例化std::is_function<bar>并std::enable_if<true, bool>包含在构建输出中,增加其大小(尽管对于此示例来说是微不足道的):
#include <type_traits>
template<typename F,
typename = std::enable_if_t<
std::is_function<F>::value,
bool> = true>
void foo(F& f)
{
// do some stuff with f
}
void g();
int main()
{
foo(g);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果使用基于的 C++20 概念std::is_function,显然模板必须被实例化以检查它。但是那个实例化然后写入最终的构建输出吗?这是否因编译器实现而异?
#include <type_traits>
template<typename F>
concept Function = std::is_function<F>::value;
template<Function F>
void foo(F& f)
{
// do some stuff with f
}
//...
Run Code Online (Sandbox Code Playgroud) C++20引入了一个比较概念boolean-testable,但是我注意到它的斜体和中间的连字符,说明它只是为了exposition-only,由于没有所谓的std::boolean_testablein <concepts>,我们自己也不能使用代码。
这个仅用于展示的概念的目的是什么?为什么这个概念如此神秘?
考虑这个例子:
#include <iostream>
#include <utility>
template<typename T>
concept Printable = requires(const T a) {
a.print();
};
template<typename T>
constexpr auto is_printable() {
return Printable<T>;
}
template<class T, std::enable_if_t<is_printable<T>()>* = nullptr>
constexpr void do_print(T data) {
data.print();
}
struct foo {
void print() const {
std::cout << "Hello World\n";
}
};
int main() {
foo f;
do_print(f);
}
Run Code Online (Sandbox Code Playgroud)
尝试在 MSVC(版本 16.9.4,/std:c++latest)上编译它会产生以下错误:
Error C2783 'void do_print(T)': could not deduce template argument for '__formal'
Error C2672 'do_print': no matching overloaded function found
Run Code Online (Sandbox Code Playgroud)
它未能满足 …
我想创建一个包含不同类型但共享相同概念的对象的向量(或数组)。
类似于Vec<Box<dyn trait>>Rust。
struct Dog {
void talk() {
std::cout << "guau guau" << std::endl;
}
};
struct Cat {
void talk() {
std::cout << "miau miau" << std::endl;
}
};
template <typename T>
concept Talk = requires(T a) {
{ a.talk() } -> std::convertible_to<void>;
};
int main() {
auto x = Dog{};
auto y = Cat{};
??? pets = {x, y};
for(auto& pet: pets) {
pet.talk();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我在回顾 C++20 特性时发现了概念。我发现他们向模板参数添加了验证,但除此之外,我不明白 C++20 概念的真实用例是什么。
C++ 已经有类似的东西std::is_integral,它们可以很好地执行验证。
我确定我遗漏了一些关于 C++20 概念及其支持的内容。
您可能知道std::max并std::min“受苦”,因为它们有 1 个模板参数,因此即使简单max(container.size(), 47)也行不通,因为 .size() 返回size_t而 47 是int。
我知道历史上曾有人提议向 C++ 添加适当的重载,但被拒绝了。但据我所知,这主要是由于纸张过于复杂而无法获得足够的收益,所以我想知道是否可以将其std::common_range_t用作返回值(发明的类型特征使您的 int/float 足够大以容纳混合参数的最小值/最大值,否则会出现硬错误)那会好吗...
所以最终得到我的问题:如果我们希望 min/max 扩展为采用 2 如上所述的模板参数,是否有任何向后兼容性或任何其他问题阻止了这一点?
笔记: