C++ 20个概念真正解决了什么问题?
我试图了解C ++ 20个概念正在解决哪些问题,以及它们对最终用户的准确有用。我知道它可以帮助编译器解决函数调用,但是从我对其的粗略阅读来看,从最终用户的角度来看,它似乎并没有增加太多。
考虑以下代码:
void addToCollection(auto& collection, const auto& val) {
collection.push_back(val);
}
int main() {
vector<int> fooVec;
addToCollection(fooVec, 15);
unordered_set<int> fooSet;
addToCollection(fooSet, 15);
return 0;
}
编译器发出的一个非常明显的消息告诉我们函数addTocollection
与Unordered_set
不兼容。
error: no member named 'push_back' in 'std::unordered_set<int>'
collection.push_back(val);
~~~~~~~~~~ ^
concept.cpp:34:5: note: in instantiation of function template specialization 'addToCollection<std::unordered_set<int>, int>'
requested here
addToCollection(fooSet, 15);
在概念之前,您将通过提供明确的模板专业化来解决这样的失败。
template<>
void addToCollection(unordered_set<int>& collection, const auto& val) {
collection.insert(val);
}
使用概念,看来解决此问题的正确方法是通过对功能参数类型的约束来约束。
template<typename CollectionType>
concept HasPushBack = requires(CollectionType collection, typename CollectionType::value_type val) {
collection.push_back(val);
};
void addToCollection(HasPushBack auto& collection, const auto& val) {
collection.push_back(val);
}
void addToCollection(auto& collection, const auto& val) {
collection.insert(val);
}
作为最终用户,我看不到在此示例中我从概念中获得什么优势 - 为什么我应该练习定义类型约束时,而实际上我可以提供明确的模板专业化并完成?
I'm trying to understand what problems C++20 concepts are solving and how exactly they are helpful to the end user. I understand that it helps the compiler in resolving function calls, but from my cursory reading of it, from an end user standpoint, it doesn't seem to add much.
Consider this code:
void addToCollection(auto& collection, const auto& val) {
collection.push_back(val);
}
int main() {
vector<int> fooVec;
addToCollection(fooVec, 15);
unordered_set<int> fooSet;
addToCollection(fooSet, 15);
return 0;
}
The compiler issues a very obvious message telling us the function addToCollection
is not compatible with unordered_set
.
error: no member named 'push_back' in 'std::unordered_set<int>'
collection.push_back(val);
~~~~~~~~~~ ^
concept.cpp:34:5: note: in instantiation of function template specialization 'addToCollection<std::unordered_set<int>, int>'
requested here
addToCollection(fooSet, 15);
Prior to concepts, you'd resolve a failure like this by providing an explicit template specialization.
template<>
void addToCollection(unordered_set<int>& collection, const auto& val) {
collection.insert(val);
}
With concepts, it appears that the correct way to fix this is by placing a constraint on the function parameter type.
template<typename CollectionType>
concept HasPushBack = requires(CollectionType collection, typename CollectionType::value_type val) {
collection.push_back(val);
};
void addToCollection(HasPushBack auto& collection, const auto& val) {
collection.push_back(val);
}
void addToCollection(auto& collection, const auto& val) {
collection.insert(val);
}
As an end user I don't see what advantages I get from concepts in this example—why should I go through the exercise of defining a type constraint when in fact, I could provide an explicit template specialization and be done?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,不要误认为可以将工具用于该工具的“目的”的方式。您的可以用螺丝刀的对接末端钉住钉子,但这不是我们制造螺丝刀的原因。
即便如此,这里的区别在于,您的概念化版本可用于更多类型。您的专业版本仅适用于
unordered_set
和unordered_set&lt; int&gt;
。任何其他类型(unordered_set&lt; float&gt;
,set&lt; int&gt;
等)都会失败。该概念化版本适用于任何类型的使用push_back
或insert
(尽管我还将检查insert
,以便您获得更好的错误如果类型没有插入
)。其次,这个示例并非真正锻炼概念。您的代码在这里并没有真正定义“概念”;这只是对单个特定成员功能的测试。
当您构建一系列重要要求以及它们之间的关系时,概念是一种功能。迭代器和范围是其实用程序作为功能的示例。
在概念之前,您可以对此功能声明说些什么:
嗯,从所使用的文本中,参数有望为“ inputiterator”。但是...这是什么意思? “ inputiterator”只是文本;它本身并不意味着什么。您必须转到功能的文档来弄清楚这一点。
如果您使用基本类别使用动态多态性,则可以进入基类,看看预期的接口需要什么。派生类的要求将由C ++代码本身阐明。
概念是用于编译时间静态多态性的工具。这是一种使用实际的C ++代码来拼写模板的接口要求的方法,以便用户可以对他们期望提供的内容有所了解。它还确保用户实际提供该接口。
它使您可以根据这些接口过载。不仅功能过载,还可以超载。您可以将阶级模板及其成员功能限制在概念上。
您可以轻松地制作一个类模板,该模板采用任何类型的迭代器,并生成匹配任何类型的迭代器的接口。如果给定的迭代器仅是
input_iterator
,则可以仅生成input_iterator
函数。如果是rando_access_iterator
,那么您也可以生成这些功能。尽管您可以通过Sfinae在Pre-C ++ 20中这样做(请参阅在这里在这里)技术,具有概念,这是尽可能小的。First, do not mistake a way that a tool can be used for "the purpose" of that tool. You can hammer a nail in with the butt-end of a screwdriver, but that isn't why we make screwdrivers.
Even so, the difference here is that your conceptualized version works on more types. Your specialized version only worked for
unordered_set
and only forunordered_set<int>
. Any other type (unordered_set<float>
,set<int>
, etc) would fail. The conceptualized version works for any type with apush_back
orinsert
(though I would also check forinsert
, so that you'd get a better error if the type doesn't haveinsert
).Second, this example doesn't really exercise concepts. Your code doesn't really define a "concept" here; it's just a test for a single, specific member function.
Concepts as a feature shine when you are building a series of significant requirements, with relationships between them. Iterators and ranges are the go to examples for their utility as a feature.
Before concepts, what can you say about this function declaration:
Well, from the text used, the parameter is expected to be an "InputIterator". But... what does that mean? "InputIterator" is just text; it doesn't mean anything by itself. You'd have to go to the documentation of the function to figure that out.
If you were using dynamic polymorphism with base classes, you could just go to the base class and see what the expected interface needs to be. The requirements of a derived class would be spelled out by the C++ code itself.
Concepts is a tool for doing that for compile-time static polymorphism. It is a way for spelling out the interface requirements of a template using actual C++ code, such that a user can have some idea of what they're expected to provide. It also ensures that the user actually provides that interface.
And it allows you to overload based on these interfaces. Not just function overloading, but class overloading. You can constrain class templates, and their member functions, on concepts.
You can easily make a class template that takes an iterator of any kind and generates an interface matching whatever kind of iterator is given to it. If the given iterator is only an
input_iterator
, then you can generate just theinput_iterator
functions. If it's arandom_access_iterator
, then you can generate those functions too. And while you could do that in pre-C++20 via SFINAE (see here & here) techniques, with concepts, this is about as trivial as it gets.C ++ 20个概念主要解决一个问题:错误消息人类可以阅读。
它们也可以使代码更可读性,但这是更重要的。
C++20 concepts primarily solve one problem: Error messages a human being can read.
They can make the code more readable too but that is more secondary.