15

我在看这个源代码

template<char... digits>
struct conv2bin;

template<char high, char... digits>
struct conv2bin<high, digits...> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0') * (1 << sizeof...(digits)) + 
                             conv2bin<digits...>::value;
};

template<char high>
struct conv2bin<high> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0');
};

template<char... digits>
constexpr int operator "" _b() {
    return conv2bin<digits...>::value;
}

int array[1010_b];

我想知道这是否甚至是有效的C++。

template<char high, char... digits>
struct conv2bin<high, digits...> {

这是什么?不专业的模板专业化?

为什么结构声明里面有代码行

struct conv2bin<high> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0');
};

我很困惑..

4

2 回答 2

22

您的代码显示了三个新的 C++11 功能:可变参数模板用户定义的文字静态断言

通用可变参数类模板分别指定零个或多个参数,一个或多个专用版本,以及恰好一个。

// digits can be the empty set, so 0 or more arguments
template<char... digits>
struct conv2bin;

// digits can be the empty set, so 1 or more arguments
template<char high, char... digits>
struct conv2bin<high, digits...>

// fully specialized for 1 argument
template<char high>
struct conv2bin<high>

可变参数模板的完整语法有点古怪,维基百科上有一篇不错的文章。它对另一个 C++11 特性特别有用:完美转发可变数量的函数参数。

异国情调的外观int operator "" _b()定义了一个用户定义的文字,这是一种将您自己的单位添加到您的类型和表达式的方法。它只是意味着后面的整数_b被标记为某个“单位”。有关更多详细信息,请参阅此问题。一个实际的好处是避免未来的火星着陆器崩溃(国际单位制和英制单位在他们的着陆软件中混合,编译器无法诊断它)。

Thestatic_assert完全按照你的想法做:它静态地断言它的条件,即在compile-time。当断言失败时,编译停止。这是尽快检测错误的好方法。

更新

当您有部分重叠的参数范围时,可变参数模板的专业化可能会非常令人惊讶:零个或多个参数版本只会匹配您示例中的空列表(如果您已经为其提供了定义)。

#include <iostream>

template<int... Args>
struct Test
{
   enum { value = 0 }; 
};

template<int I, int... Args>
struct Test<I, Args...>
{
   enum { value = 2 };
};

template<int I>
struct Test<I>
{
   enum { value = 1 };
};

int main()
{
   std::cout << Test<>::value << "\n";     // matches zero or more version
   std::cout << Test<0>::value << "\n";    // matches single argument version
   std::cout << Test<0, 0>::value << "\n"; // matches one or more version, not the zero or more one!
}

LiveWorkSpace上输出。

这当然是部分模板特化的一般规则的一个例子,它指出将选择最特化的版本(一个或多个比零个或多个更特化,因为后者总是可以用于前者可以,但反之不行)。但是因为可变参数模板通常彼此之间没有那么“明显”的不同,所以你应该特别注意它们的部分特化。

于 2013-04-15T17:47:53.443 回答
1
template<char... digits>
struct conv2bin;

这是一个模板前向声明。它不必完全定义,因为如果以不受支持的方式使用它,您会更快地发现错误(编译将失败)。这个特定示例不会导致编译失败,因为专业化涵盖了所有可能的情况。

template<char high, char... digits>
struct conv2bin<high, digits...> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0') * (1 << sizeof...(digits)) + 
                             conv2bin<digits...>::value;
};

这是一种部分特化,其中设置了一个模板值。其余的只是转发到模板类型的“较低层级”。这个模板结构是完全定义的,并且包含一个 int 成员变量,其值取决于“高”值和下一个模板。

template<char high>
struct conv2bin<high> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0');
};

再次部分模板特化,定义模板参数在其列表中仅包含一个参数时的值。

所以,总的来说,这是一个使用可变参数模板的模板元编程


静态断言用于限制模板变量可以采用的值。

于 2013-04-15T18:12:26.053 回答