Концепции навязывают 2-й аргумент типа int

#c #c 20

#c #c 20

Вопрос:

Как следует из названия, я хочу foo принимать int type только в качестве 2-го параметра.

 #include <iostream>
#include <concepts>
#include <type_traits>

template <typename U, typename T>  concept IS_INT =
requires (U u, T t) {
        { t   0 } -> std::same_as<int>;
};


IS_INT {U, T}
void foo (U u, T t)
{
        std::cout << "IS INT!" << std::endl;
        return;
}


int main()
{
        foo(1, 1);
        return 0;
}
  

Он работает, но g (версия 10.2.0) генерирует это предупреждение

 test.cpp:11:8: warning: template-introductions are not part of C  20 concepts [-fconcepts-ts]
   11 | IS_INT {U, T}
      | ~~~~~~~^~~~~~
  

Альтернативный способ записи IS_INT {U, T} ? чтобы избавиться от этого предупреждения?


Наконец, как переписать это ограничение (t равно int) без необходимости добавлять 0?

     { t   0 } -> std::same_as<int>;
  

Редактировать:

 template <typename U, typename T>  concept IS_INT =
requires (U u, T t) {
        std::same_as<T, int>;
};
  

Не выдает ошибку компиляции для

 foo(1, "TTT");
  

Комментарии:

1. IS_INT {U, T} Что это за синтаксис? { t 0 } Вы хотите, чтобы повышенный тип был int или тип был int ?

2. @KamilCuk en.cppreference.com/w/cpp/experimental/constraints

3. Тогда вы хотите std::same_as<T, int> , чтобы не t 0 было int . оператор будет продвигать свои операнды.

4. @KamilCuk да, но если я изменю тело { t 0 } -> std::same_as<int>; на std::same_as<T, int>; in main для foo(1, "TTT") , я не получу ошибку компиляции. Я предполагаю, что я злоупотребляю понятиями…

Ответ №1:

Вы можете сохранить двоичную форму даже в текущей версии core concepts:

 template <typename U, typename T>  concept IS_INT =
requires (U u, T t) {
        { t   0 } -> std::same_as<int>;
};


template<class T, IS_INT<T> U>
void foo (U u, T t)
{
        std::cout << "IS INT!" << std::endl;
        return;
}
  

(обратите внимание на обратный порядок параметров: как правило, если концепция принимает несколько параметров, то только первый из них является особенным, а U стоит первым в вашем определении). Полный TS-сахар, как предупреждает g , в настоящее время не является стандартным.

Наконец, как переписать это ограничение (t равно int) без необходимости добавлять 0?

 template<class T, class U> concept is_int = std::same_as<T, int>;
  

?

Комментарии:

1. О, переход { t 0 } -> std::same_as<int>; на std::same_as<T, int>; этот простой … и template<class T, IS_INT<T> U> это то, что мне было нужно. Спасибо!

2. Я только что заметил, изменив { t 0 } -> std::same_as<int>; на std::same_as<T, int>; will not выдаст ошибку, в foo(1, "TTT") то { t 0 } -> std::same_as<int>; время как does . Я что-то упускаю?

3. @TonyTannous да. Одно из них — это вложенное требование, которое должно быть выполнено, другое — всего лишь одно выражение, которое компилируется в любом случае и на самом деле ничего не ограничивает.

Ответ №2:

Как следует из названия, я хочу, чтобы foo принимал только int type в качестве своего 2-го параметра.

Это требует унарной концепции — вы хотите ограничить 2-й параметр, сам по себе, быть int . Это проверка требования одного типа.

Это:

 template <typename U, typename T>  concept IS_INT =
  

является двоичным понятием (независимо от того, что следует за = ). Это ограничивает два разных типа, T и U , в некотором роде. Независимо от того, что вы пишете после этого, на самом деле это не касается вашего варианта использования.

Вы хотите сказать, что тип — это an int . То есть:

 template <typename T> concept is_int = std::is_same_v<T, int>;
  

Который вы можете использовать, таким образом:

 template <typename U, is_int T>
void foo (U u, T t);
  

Это не имеет ограничений на первый параметр, а второй параметр должен иметь тип int .


Теперь стандартная библиотека фактически поставляется с концепцией именно для этой проблемы. Он называется same_as :

 template <typename U, std::same_as<int> T>
void foo (U u, T t);
  

Кроме того, стоит отметить требование:

 { t   0 } -> std::same_as<int>;
  

На самом деле не требует t наличия типа int . Это справедливо и для любого целочисленного типа, приведенного ниже int , из-за целочисленного продвижения.

Комментарии:

1. Спасибо за ответ (уже 1) Наверное, я не понимаю, когда использовать требования и накладывать ограничения в {} блоке. Еще раз спасибо.