Вывод параметров шаблона, не являющегося типом

Можно ли вывести значение шаблона (не тип) для функции c ++ 17?

Функция foo:

template<int I>
int foo()
{
    return (I);
}

Можно вызвать через:

foo<5>();

И вернет 5.

Типы шаблонов можно определить по типу аргумента функции. Можно ли как-то сделать то же самое для значения шаблона? Например:

template<int I = x>
int bar(const int x)
{
    return (I);
}

Очевидно, это не сработает (потому что перед объявлением требуется один x), но может ли быть какой-нибудь трюк C ++ 17, который позволил бы это сделать?

Я хотел бы использовать это как способ установки аргумента функции постоянного выражения.


person user7119460    schedule 23.05.2018    source источник
comment
Неа. C ++ так не работает. Параметры шаблона всегда выводятся во время компиляции. Вы не знаете, какие параметры получает функция до времени выполнения.   -  person Sam Varshavchik    schedule 23.05.2018
comment
Зачем тебе это нужно? Каков вариант использования передачи значения как в качестве шаблона, так и в качестве аргумента?   -  person Some programmer dude    schedule 23.05.2018
comment
Обратите внимание, что возможно и обратное: template<int X> int bar(const int x = X) { ... }   -  person Some programmer dude    schedule 23.05.2018
comment
@Someprogrammerdude: Каков вариант использования для передачи значения как в качестве шаблона, так и в качестве аргумента? Поскольку C ++ не имеет constexpr параметров. Но параметры шаблона, не являющиеся типом, всегда являются постоянными выражениями. Таким образом, было бы полезно иметь возможность вызывать (предположительно constexpr функцию с параметром, который она может рассматривать как constexpr. Пока мы не получим реальные constexpr параметры, вам нужно найти обходной путь с параметрами шаблона.   -  person Nicol Bolas    schedule 23.05.2018
comment
@NicolBolas Я знаю, но я все еще не вижу смысла передавать его both в качестве шаблона, и в качестве аргумента. За исключением возможности не использовать синтаксис <X> при вызове функции. Если в константном выражении используется только шаблон? Или сделать всю функцию constexpr и передать аргумент постоянного выражения (если возможно)?   -  person Some programmer dude    schedule 23.05.2018


Ответы (2)


То, что вы хотите, может быть сделано только (ab) с использованием вывода типа для целочисленного вывода. Наблюдать:

template<int x>
struct integer_value {};

template<int x>
void test(integer_value<x> val)
{
  //x can be used here.
}

Конечно, вы должны вызывать это с помощью test(integer_value<4>{}) или чего-то подобного.

person Nicol Bolas    schedule 23.05.2018
comment
FWIW @ op, самое простое написание этого слова в Boost.Hana - test(5_c). Можно получить почти точный желаемый синтаксис вызова. - person chris; 23.05.2018
comment
@chris: Конечно. Но реализация _c, насколько я понимаю, решительно нетривиальна. Вы должны фактически проанализировать <char ...> форму синтаксиса UDL. Если у вас нет лучшего решения? - person Nicol Bolas; 23.05.2018
comment
Да, прискорбно. Я ожидаю, что одна из этих возможностей, связанных с параметром constexpr, удастся и даст нам что-то лучшее. - person chris; 23.05.2018

template<auto x>
using constant = std::integral_constant< std::decay_t<decltype(x)>, x >;

шаблон

using constant = std::integral_constant< std::decay_t<decltype(x)>, x >;
constexpr int digit_val( char c ) {
    if (c >= '0' && c <='9')
        return c-'0';
    else if (c >= 'A' && c <= 'Z')
        return c-'A'+10;
    else if (c >= 'a' && c <= 'z')
        return c-'a'+10;
    else
        throw nullptr;
}
constexpr long long ce_pow( int base, int count, long long acc=1 ){
  if (!count) return acc;
  return ce_pow( base, count-1, acc*(long long)base );
}
constexpr long long from_digits( long long acc, int base ){
  return acc;
}
template<int I, int...Is>
constexpr long long from_digits( long long acc, int base, constant<I>, constant<Is>... ) {
  return from_digits( acc+ce_pow(base, sizeof...(Is))*(long long)I, base, constant<Is>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<'x'>, constant<cs>... ){
  return from_digits( 0, 16, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<'b'>, constant<cs>... ){
  return from_digits( 0, 2, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr long long val( constant<'0'>, constant<cs>... ){
  return from_digits( 0, 8, constant<digit_val(cs)>{}... );
}
template<char...cs>
constexpr auto operator""_k(){
    return constant< val( constant<cs>{}... ) >{};
}

или что-то в этом роде. В настоящее время:

template<int I>
int bar(constant<I>)
{
  return (I);
}

должен работать с bar(5_k);. У меня могут быть опечатки, причудливый шаблон auto constant может блокировать вычеты, а поддержка 0X и 0B отсутствует. Но в остальном это звук.


Альтернативная реализация на основе цикла:

struct number_format {
    int prefix = 0;
    int base = 0;
};
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'x'>, constant<cs>... ) {
    return {2,16};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'X'>, constant<cs>... ) {
    return {2,16};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'b'>, constant<cs>... ) {
    return {2,2};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<'B'>, constant<cs>... ) {
    return {2,2};
}
template<char...cs>
constexpr number_format get_format( constant<'0'>, constant<cs>... ) {
    return {1,8};
}
template<char...cs>
constexpr number_format get_format( constant<cs>... ) {
    return {0,10};
}
template<char...Cs>
constexpr long long val( constant<Cs>...cs ){
  char buff[] = {Cs...};
  constexpr number_format fmt = get_format( cs... );

  long long r = 0;
  for (auto it = std::begin(buff)+fmt.prefix; it != std::end(buff); ++it) {
      r *= fmt.base;
      r += digit_val(*it);
  }
  return r;
}
template<char...cs>
constexpr auto operator""_k(){
    return constant< val( constant<cs>{}... ) >{};
}

живые примеры.

person Yakk - Adam Nevraumont    schedule 23.05.2018
comment
Вы можете почти сразу же поместить символы в массив и проанализировать его в обычном режиме. - person T.C.; 23.05.2018
comment
@ T.C. Конечно. С другой стороны, переключение формата через перегрузку - это слишком весело, но я написал синтаксический анализатор на основе цикла. - person Yakk - Adam Nevraumont; 23.05.2018