空值包扩展是否与类型包或可选类型参数匹配



我只是想破解一个二进制文字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:此代码实际上只需进行小的调整即可工作;请看下面的答案。但这并不能直接解决问题。嗯,也许我应该编辑这个而不是回答…

在一个字符处终止递归不是更好吗?

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需要在可变版本之前声明,正如Clang很好地指出的那样:

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() {

没有关于这种棘手匹配的合规性的官方说法,但如果两个重载互换,给定的代码确实有效。

第二个终止重载对第一个重载不可见,因为第一个重载在模板定义时解析名称。只有依赖于模板参数的函数调用的查找延迟到实例化时。

需要明确的是,这是有效的

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.
}

最新更新