Соответствует ли пустое расширение пакета значений пакету типов или дополнительному параметру типа?

StackOverflow https://stackoverflow.com/questions/9500611

Вопрос

Я просто пытался взломать двоичный литерал operator ""_b, но застрял при попытке завершить рекурсию.Как определить функцию, которую можно вызвать с использованием пустого явного списка параметров шаблона, которая не конфликтует с перегрузкой пакета параметров?Затем вдохновение:сопоставьте расширение пустого пакета с чем-то дурацким.

Но GCC жалуется, что несуществующие типы пустого списка аргументов не согласуются с неявно обязательными типами списка параметров.Должно ли это работать таким образом?

template< char head, char ... tail >
constexpr unsigned long long parse_binary() {
    return ( ( head - '0' ) << sizeof ... (tail) )
        + parse_binary< tail ... >(); // Error: no overload for termination.
}

template< typename = void > // I want this to match an empty pack of chars.
// template< short = 0 > // even this would do.
constexpr unsigned long long parse_binary() {
    return 0;
}

template< char ... digits >
constexpr unsigned long long operator ""_b() {
    return parse_binary< digits ... >();
}

#include <iostream>

int main() {
    std::cout << 010101_b << '\n';
}

Примечание:Вопрос не реализуется operator ""_b.Эту проблему можно решить, расширив пакет в список параметров и передав std::integral_constant типа вокруг.

Заметка 2:Этот код действительно работает с небольшой поправкой;см. мой ответ ниже.Но это не решает вопроса напрямую.Хм, возможно, мне следовало отредактировать это вместо того, чтобы отвечать…

Это было полезно?

Решение 2

Официальных слов о соответствии такого сложного сопоставления нет, но данный код делает работать, если две перегрузки транспонированы.

Вторая завершающая перегрузка не видна первой, поскольку первая разрешает имя во время определения шаблона.Только вызовы функций, зависящие от параметра шаблона, откладывают поиск до момента создания экземпляра.

Просто быть чистым, это работает:

template< typename = void > // Define this one first!
constexpr unsigned long long parse_binary() {
    return 0;
}

template< char head, char ... tail >
constexpr unsigned long long parse_binary() {
    return ( ( head - '0' ) << sizeof ... (tail) )
        + parse_binary< tail ... >(); // Bingo: overload found.
}

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

Не лучше ли было бы прекратить рекурсию на одном символе?

template<char Ch>
constexpr unsigned long long parse_binary(){
  return Ch - '0';
};

// second head to disambiguate
template< char head1, char head2, char ... tail >
constexpr unsigned long long parse_binary() {
    return ( ( head1 - '0' ) << sizeof ... (tail)+1 ) + parse_binary< head2, tail ... >();
}

В любом случае проблема в том, что parse_binary для нулевых символов необходимо объявить перед вариационной версией, как хорошо указывает Кланг:

error: call to function 'parse_binary' that is neither visible in
      the template definition nor found by argument-dependent lookup

// call trace...

note: 'parse_binary' should be declared prior to the call site
      constexpr unsigned long long parse_binary() {
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top