Отключить не шаблонные методы с концепциями - PullRequest
3 голосов
/ 14 октября 2019

Есть ли синтаксис для ограничения не шаблонного метода? Все синтаксисы, которые я пробовал на godbolt с понятиями clang: branch и gcc не компилируются:

// these examples do not compile

template <bool B>
struct X
{
    requires B
    void foo() {}
};

template <class T>
struct Y
{
    requires (std::is_trivially_copyable_v<T>)
    auto foo() {}
};

Трюк для его компиляции такой же, как и для SFINAE, создайте шаблон методов,хотя они на самом деле не являются шаблонами. И, как ни странно, ограничение, похоже, не нуждается в шаблоне метода, оно может нормально работать только с шаблоном класса, поэтому я действительно надеюсь, что есть способ применить ограничения с концепциями, не прибегая к старым хаки:

// old hacks

template <bool B>
struct X
{
    template <bool = B>
    requires B
    auto foo() {}
};

template <class T>
struct Y
{
    template <class = T>
    requires std::is_trivially_copyable_v<T>
    auto foo() {}
};

Пример из реальной жизни:

template <class T, bool Copyable_buf = false>
struct Buffer
{
    /* ... */

    requires Copyable_buf
    Buffer(const Buffer& other)  {}

    /* ... */
};

template <class T>
using Copyable_buffer = Buffer<T, true>;

Ответы [ 2 ]

3 голосов
/ 14 октября 2019

Чтобы поддержать другой ответ на этот вопрос, вот нормативная формулировка об этом из последнего стандартного черновика:

[dcl.decl]

1 Декларатор объявляет одну переменную, функцию или тип в объявлении. Список инициализатора-объявления, появляющийся в объявлении, представляет собой разделенную запятыми последовательность объявлений, каждый из которых может иметь инициализатор.

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator
init-declarator:
    declarator initializer<sub>opt</sub>
    declarator requires-clause

4 Необязательный параметр require-clause ([temp]) в init-деклараторе или элементе-деклараторе не должно присутствовать, когда декларатор не объявляет функцию ([dcl.fct]). Когда присутствует после объявления, предложение require называется конечным предложением require. Завершающее предложение require представляет выражение-ограничение, которое получается в результате интерпретации логического-или-выражения-ограничения как выражения-ограничения. [Пример:

void f1(int a) requires true;               // OK
auto f2(int a) -> bool requires true;       // OK
auto f3(int a) requires true -> bool;       // error: requires-clause precedes trailing-return-type
void (*pf)() requires true;                 // error: constraint on a variable
void g(int (*)() requires true);            // error: constraint on a parameter-declaration

auto* p = new void(*)(char) requires true;  // error: not a function declaration

- конец примера]

Как указано в этих двух абзацах, в конце объявления функций может появиться конечное условие require. Его смысл состоит в том, чтобы ограничить функцию константным выражением, которое она принимает в качестве аргумента (который включает понятия).

3 голосов
/ 14 октября 2019

Да, есть! Условие require может появляться как последний элемент объявления функции, и в этом случае оно позволяет ограничивать не шаблонные методы (или свободные функции в этом отношении):

// This works as expected! Yey!!

template <class T, bool Copyable_buf = false>
struct Buffer
{
    Buffer(const Buffer& other) requires Copyable_buf
    {
        // ...
    }
};

template <bool B>
struct X
{
    auto foo() requires B
    {
        // ...
    }
};

template <class T>
struct Y
{
    auto foo() requires std::is_trivially_copyable_v<T>
    {
        // ...
    }
};

Этот ответ является эмпирическим и основан на тестировании текущих реализаций концепций. Испытание Годболта . В ответе Storry Tellers приведены стандартные цитаты, подтверждающие это поведение.

...