这段代码是什么意思?

时间:2011-01-28 05:56:09

标签: c++ templates

这是静态断言技巧的一部分。我无法理解非专业化的类是如何工作的。有人可以向我解释一下吗?

编辑:带宏的完整代码:(取自http://www.skynet.ie/~caolan/Fragments/C++StaticAssert.html

#ifndef STATICASSERT_HXX
#define STATICASSERT_HXX
/*
 Lifted direct from:
 Modern C++ Design: Generic Programming and Design Patterns Applied
 Section 2.1
 by Andrei Alexandrescu
*/
namespace ww
{
    template<bool> class compile_time_check
    {
    public:
        compile_time_check(...) {}
    };

    template<> class compile_time_check<false>
    {
    };
}

    /*
    Similiar to assert, StaticAssert is only in operation when NDEBUG is not
    defined. It will test its first argument at compile time and on failure
    report the error message of the second argument, which must be a valid c++
    classname. i.e. no spaces, punctuation or reserved keywords.
    */
#ifndef NDEBUG
#   define StaticAssert(test, errormsg)                         \
    do {                                                        \
        struct ERROR_##errormsg {};                             \
        typedef ww::compile_time_check< (test) != 0 > tmplimpl; \
        tmplimpl aTemp = tmplimpl(ERROR_##errormsg());          \
        sizeof(aTemp);                                          \
    } while (0)
#else
#   define StaticAssert(test, errormsg)                         \
    do {} while (0)
#endif

#endif

2 个答案:

答案 0 :(得分:5)

宏以类似于此的方式调用此代码:

compile_time_check<static expression> temp(Error_Some_Struct_here);

因此,例如,你可以这样做:

compile_time_check<sizeof(Foo) < sizeof(Bar)> temp(Error_Foo_must_be_smaller_than_Bar);

sizeof(Foo)小于sizeof(Bar)时,模板会设置非专业版本:

template<bool> class compile_time_check
{
public:
    compile_time_check(...) {}  //What is this?
};

并且代码基本上“编译”到此类的实例:

compile_time_check temp(Error_Foo_must_be_smaller_than_Bar);

,如果是空的并且什么也不做,编译器可以删除死代码。 Bam,没有运行时开销,已完成。

另一方面,如果sizeof(Foo)大于或等于sizeof(Bar),则会改为显示专业版:

template<> class compile_time_check<false>
{
};

它将尝试调用构造函数compile_time_check::compile_time_check(struct),但由于它不存在,因此编译错误。这是你想要的,因为静态断言只应在断言为真的情况下编译。

我认为,构造函数采用可变参数列表的原因有两个:

  1. 确保它不会调用专用版本所具有的默认构造函数。它的可变参数使您可以将任何结构作为错误“字符串”传递。或者,这可能是模板化的,构造函数可能已经将模板对象作为参数。
  2. 这样就可以传入错误消息。当assert为true时,忽略它并且没有任何反应,编译器优化器会删除代码。但是,如果断言为false,则错误字符串应显示在错误消息中。或许像constructor not found for compile_time_check::compile_time_check(ERROR_Assertion_error_blah())这样的东西。
  3. 一个替代的,无模板(我相信它经常在C中使用),我以前见过的静态断言是这样的:

    #define compile_time_assert(pred) switch(0){case: 0: case pred:;}
    

    这是有效的,因为如果pred为false,则代码最终为switch(0){case: 0: case 0:;},并且具有相同常量的两个案例标签是错误的。 In depth explanation here

答案 1 :(得分:3)

暂时摆脱命名空间(因为它基本上无关紧要),你所拥有的是:

template<bool> class compile_time_check
{
public:
    compile_time_check(...) {}  //What is this?
};

这是一个类模板。它有一个类型为bool的非类型模板参数和一个可变参数构造函数,因此它将接受任何参数。

template<> class compile_time_check<false>
{
};

这是值false的上一个模板的特化。因此,当您实例化compile_time_check<false> checker;时,它将使用这个。这个特化有一个默认的构造函数(从未使用过),但是 no 构造函数将接受一个参数。

意图是这只是从这里使用过:

    typedef ww::compile_time_check< (test) != 0 > tmplimpl; \
    tmplimpl aTemp = tmplimpl(ERROR_##errormsg());          \
    sizeof(aTemp);                                          \

在这种情况下,我们使用ctor参数实例化一个tmplimpl对象。如果模板参数为true,那么它将起作用,但是如果模板参数为false,它将使用上面的专门化,它只有一个默认的ctor,而不是一个带参数的那个 - 所以编译器会打印出来一条错误消息,上面写着:

error: no ctor found for compile_time_check<condition>("<error message>");

后续的sizeof(aTemp);用于强制在编译时对该对象进行求值,因此我们将此视为编译器错误消息而不是链接器错误,指出compile_time_check::compile_time_check<false>()是未解析的外部。 / p>