Частичная специализация с использованием понятий

Я просто читал примеры концепций С++ 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

Мой вопрос

Можно ли специализироваться с помощью концепций?

Я не уверен, что можно определить функцию с помощью void Bar<T> {}. Это недопустимый синтаксис.

ForceBru 19.03.2019 06:18

@ForceBru Есть ли альтернатива, которая использует концепции для выполнения той же задачи?

Mohit 19.03.2019 06:20

Если под «той же задачей» вы подразумеваете «частично специализировать шаблон функции», то нет. С++ никогда не позволял этого, концепции или нет. Функции и шаблоны функций могут быть только перегружены.

StoryTeller - Unslander Monica 19.03.2019 06:23

@StoryTeller Можете ли вы сказать мне, почему С++ не позволяет использовать этот код?

Mohit 19.03.2019 06:27

Ваш конкретный код? Потому что это синтаксически неправильно. Если вы имеете в виду частичную специализацию шаблонов функций в целом, это выходит за рамки этого вопроса. Но, вероятно, на SO есть вопросы и ответы по этому поводу.

StoryTeller - Unslander Monica 19.03.2019 06:29

@StoryTeller Спасибо, я понял. Мой код отлично работал с использованием структур.

Mohit 19.03.2019 06:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
1 035
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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).

А что касается шаблонов функций, то они могут быть только перегруженными, а не частично специализированными.

Не уверен, почему за это проголосовали, но стоит отметить, что вопрос касается специализации с использованием концепций, но вы отвечаете о специализации концепций. Это правильный ответ, но на самом деле это не то, о чем спрашивают?

Barry 19.03.2019 18:02

Это не отвечает на вопрос об использовании понятий в целях специализации, а не о том, можно ли специализировать сами понятия.

cigien 23.08.2021 03:22

Я заменил специализацию шаблона функции на специализацию структур, и мой код работает нормально. Посмотрите на следующий код.

// 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.

Код, который следует за утверждением «Концепции делать делают это проще:», не совсем демонстрирует, как понятия облегчают задачу.

P.W 20.03.2019 05:35

@П.В. Попробуйте написать эти две перегруженные версии шаблонов функций без понятий.

Barry 20.03.2019 13:21

@moyang_mm Да, это так. Если это не так, это ошибка компилятора.

Barry 15.11.2020 12:16

Другие вопросы по теме