以下concept检查类型T是否具有公共字段foo:
template<typename T>
concept has_field_foo = requires {
T::foo;
};
Run Code Online (Sandbox Code Playgroud)
有没有办法实现一个泛型concept来检查类型T是否有一个公共字段F,类似于(伪代码......字段F不能像这样传递):
template<typename T, typename F>
concept has_field = requires {
T::F;
};
Run Code Online (Sandbox Code Playgroud) 一个通用的std::atomic<T>,需要有一个T是可复制构造和复制可分配:
如果存在以下任一情况,则程序格式错误
(1.1)
is_trivially_copyable_v<T>,(1.2)
is_copy_constructible_v<T>,(1.3)
is_move_constructible_v<T>,(1.4)
is_copy_assignable_v<T>,或 (1.5)
is_move_assignable_v<T>是
false。
以上对于 C++20 来说并不陌生。编译器可能会static_assert为不符合标准的 T 发出错误。
但是,C++20 可以在语法中使用形式约束requires来正式要求上述内容作为类型的一部分,例如:
template< class T > requires
std::is_trivially_copyable_v<T> &&
std::is_copy_constructible_v<T> &&
std::is_move_constructible_v<T> &&
std::is_copy_assignable_v<T> &&
std::is_move_assignable_v<T>
struct atomic { ... };
Run Code Online (Sandbox Code Playgroud)
C++20 是否有理由避免为此目的使用形式约束?
编辑: @TC在下面的回答中正确指出:
对于
std::atomic特别是,限制主模板只是不是一种选择,给定atomic<shared_ptr<T>>和atomic<weak_ptr<T>>特在C ++ 20添加的。
有一个选项建议:
也许你可以做一些更有趣的事情(比如一个未定义和不受约束的主模板加上一个受约束的部分特化),但它增加的价值很小。
好吧,还有另一种选择,不需要 …
尝试在没有基类和虚拟调用的情况下获取编译时方法和对象选择.
情况如下:
struct A {
void f1()const { cout << "A::f1" << endl;}
void f2()const { cout << "A::f2" << endl;}
};
struct B {
void f1()const { cout << "B::f1" << endl;}
void f2()const { cout << "B::f2" << endl;}
};
class Holder {
A* _a = nullptr;
B* _b = nullptr;
public:
Holder(A* a): _a(a) {}
Holder(B* b): _b(b) {}
void f1()const {
if(_a) _a->f1();
else if(_b) _b->f1();
}
void f2()const {
if(_a) _a->f2();
else if(_b) _b->f2();
} …Run Code Online (Sandbox Code Playgroud) 有没有办法允许concept使用模板参数,可以使用提供的任何模板参数?
即模板参数占位符的某种通配符魔法?
\n一个使用示例:
\ntemplate<class Me, class TestAgainst>\nconcept derived_from_or_same_as = \n std::same_as<Me, TestAgainst> ||\n std::derived_from<Me, TestAgainst>;\nRun Code Online (Sandbox Code Playgroud)\n需要上面的内容是因为不幸的是,原始类型的 行为与和 的类类型不同。is_base_ofderived_from
现在我们可以定义一个Pair concept来检查提供的类型:
template<class P, class First, class Second>\nconcept Pair = requires(P p) {\n requires derived_from_or_same_as<decltype(p.first), First>;\n requires derived_from_or_same_as<decltype(p.second), Second>;\n};\nRun Code Online (Sandbox Code Playgroud)\n用例 [a] - 接受任何有效的As或As子类型对:
\n// this works well\nvoid doWithPairOfA(const Pair<A, A> auto& p) { /* */ }\nRun Code Online (Sandbox Code Playgroud)\n用例 …
P0847提出了对成员函数使用显式参数的可能性this。
除了该提案带来的其他好处之外,CRTP 还为没有 C、R 甚至 T 的 CRTP带来了巨大的新可能性。
在 C++ 中实现泛型的常见做法clone是基于 CRTP,例如请参阅此 SO 帖子。
鉴于我们需要clone(virtual或者至少表现为虚拟),允许:
Shape* pCopy = pShape->clone(); // get a copy of the correct runtime type
Run Code Online (Sandbox Code Playgroud)
并且鉴于建议不应声明具有显式 this 参数的成员函数virtual。
是否仍然有办法使用 P0847 来实现具有动态行为且无需 CRTP 的通用克隆?
这是一个使用以下代码的示例std::reverse_iterator:
template<typename T, size_t SIZE>
class Stack {
T arr[SIZE];
size_t pos = 0;
public:
T pop() {
return arr[--pos];
}
Stack& push(const T& t) {
arr[pos++] = t;
return *this;
}
auto begin() {
return std::reverse_iterator(arr+pos);
}
auto end() {
return std::reverse_iterator(arr);
// ^ does reverse_iterator take this `one back`? how?
}
};
int main() {
Stack<int, 4> s;
s.push(5).push(15).push(25).push(35);
for(int val: s) {
std::cout << val << ' ';
}
}
// output is as expected: …Run Code Online (Sandbox Code Playgroud)