Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does an empty value pack expansion match a type pack or optional type parameter?

I was just trying to hack up a binary literal operator ""_b, but got stuck trying to terminate the recursion. How to define a function which can be called using an empty explicit template parameter list, which doesn't conflict with a parameter pack overload? Then, inspiration: match the empty pack expansion to something wacky.

But GCC complains that the nonexistent types of the empty argument list don't agree with not-explicitly-required types of the parameter list. Is it supposed to work this way?

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';
}

Note: The question isn't implementing operator ""_b. That problem can be solved by expanding the pack into the parameter list, and passing std::integral_constant types around.

Note 2: This code actually does work with a minor adjustment; see my answer below. But that doesn't directly address the question. Hmm, maybe I should have edited this instead of answering…

like image 468
Potatoswatter Avatar asked Oct 09 '22 13:10

Potatoswatter


1 Answers

Wouldn't it be better to terminate the recursion at one character?

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 ... >();
}

In any case, the problem is that parse_binary for zero chars needs to be declared before the variadic version, as Clang nicely points out:

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() {
like image 123
Xeo Avatar answered Oct 13 '22 11:10

Xeo