Я просто читал примеры концепций С++ 20. Теперь я пытаюсь создать функцию, которая будет распечатывать, является ли данный тип хэш-таблицей или не использует концепции, смешанные с частичной специализацией. Но, к сожалению, это не работает.
#include <iostream>
#include <string>
template<typename T>
concept Hashtable = requires(T a) {
{ std::hash<T>{}(a) } -> std::size_t;
};
struct Foo {};
template <typename T>
void Bar() {
std::cout << "Type T is not a hashtable" << std::endl;
}
template <Hashtable T>
void Bar<T> {
std::cout << "Type T is a hashtable" << std::endl;
}
int main()
{
Bar<Foo>();
Bar<std::string>();
}
Я использую версию компилятора GCC HEAD 9.0.1, флаги компилятора g++ prog.cc -Wall -Wextra -I/opt/wandbox/boost-1.69.0/gcc-head/include -std=gnu++2a "-fconcepts". Это дает мне следующую ошибку компилятора:
prog.cc:18:6: error: template-id 'Bar<T>' used as a declarator
18 | void Bar<T> {
| ^~~~~~
prog.cc:18:6: error: variable or field 'Bar' declared void
prog.cc:19:54: error: expected '}' before ';' token
19 | std::cout << "Type T is a hashtable" << std::endl;
| ^
prog.cc:18:13: note: to match this '{'
18 | void Bar<T> {
| ^
prog.cc:20:1: error: expected declaration before '}' token
20 | }
| ^
Но мои ожидания были:
Type T is not a hashtable
Type T is a hashtable
Мой вопрос
Можно ли специализироваться с помощью концепций?
@ForceBru Есть ли альтернатива, которая использует концепции для выполнения той же задачи?
Если под «той же задачей» вы подразумеваете «частично специализировать шаблон функции», то нет. С++ никогда не позволял этого, концепции или нет. Функции и шаблоны функций могут быть только перегружены.
@StoryTeller Можете ли вы сказать мне, почему С++ не позволяет использовать этот код?
Ваш конкретный код? Потому что это синтаксически неправильно. Если вы имеете в виду частичную специализацию шаблонов функций в целом, это выходит за рамки этого вопроса. Но, вероятно, на SO есть вопросы и ответы по этому поводу.
@StoryTeller Спасибо, я понял. Мой код отлично работал с использованием структур.





Is it possible to specialize using concepts?
Нет, невозможно частично специализировать понятия. Согласно онлайн-справке на Ограничения и концепции:
Explicit instantiations, explicit specializations, or partial specializations of concepts are not allowed (the meaning of the original definition of a constraint cannot be changed).
А что касается шаблонов функций, то они могут быть только перегруженными, а не частично специализированными.
Не уверен, почему за это проголосовали, но стоит отметить, что вопрос касается специализации с использованием концепций, но вы отвечаете о специализации концепций. Это правильный ответ, но на самом деле это не то, о чем спрашивают?
Это не отвечает на вопрос об использовании понятий в целях специализации, а не о том, можно ли специализировать сами понятия.
Я заменил специализацию шаблона функции на специализацию структур, и мой код работает нормально. Посмотрите на следующий код.
// This file is a "Hello, world!" in C++ language by GCC for wandbox.
#include <iostream>
#include <string>
template<typename T>
concept Hashtable = requires(T a) {
{ std::hash<T>{}(a) } -> std::size_t;
};
struct Foo {};
template <typename T>
struct Boo {
static constexpr char value[] = "Type T is not a hashtable";
};
template <Hashtable HashT>
struct Boo<HashT> {
static constexpr char value[] = "Type T is a hashtable";
};
template <typename T>
void Bar() {
std::cout << Boo<T>::value << std::endl;
}
int main()
{
Bar<int>();
Bar<Foo>();
}
Шаблоны функций не могут быть частично специализированными (и никогда не могут быть). Концепции не меняют этого правила.
Однако шаблоны функций могу могут быть перегружены (и всегда могут быть). И концепции делать делают это проще:
template <typename T>
void Bar() {
std::cout << "Type T is not a hashtable" << std::endl;
}
template <Hashtable T>
void Bar() {
std::cout << "Type T is a hashtable" << std::endl;
}
int main()
{
Bar<Foo>(); // calls the first Bar
Bar<std::string>(); // calls the second Bar
}
Мы говорим, что второй Bar на более сдержанный, чем первый Bar.
Код, который следует за утверждением «Концепции делать делают это проще:», не совсем демонстрирует, как понятия облегчают задачу.
@П.В. Попробуйте написать эти две перегруженные версии шаблонов функций без понятий.
@moyang_mm Да, это так. Если это не так, это ошибка компилятора.
Я не уверен, что можно определить функцию с помощью
void Bar<T> {}. Это недопустимый синтаксис.