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

时间:2012-02-29 14:09:26

标签: c++ templates c++11 variadic-templates

我只是试图破解二进制文字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 个答案:

答案 0 :(得分:4)

终止一个字符的递归会不会更好?

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

答案 1 :(得分:0)

没有关于这种棘手匹配的合规性的官方消息,但如果转换了两个重载,则给定代码 可以正常工作。

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

为了清楚起见,这是有效的

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