2011-01-28 128 views
1

这是静态断言技巧的一部分。我无法理解非专业班是如何工作的。有人可以向我解释吗?这段代码是什么意思?

编辑:与宏全码:(从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 

回答

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

和代码基本上是“编译成”此类的instanciation:

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时,这被忽略,没有任何事情发生,编译器优化器删除代码。但是,如果断言是错误的,错误字符串应显示在错误消息中。或许像constructor not found for compile_time_check::compile_time_check(ERROR_Assertion_error_blah())

的替代,模板免费的(我相信它经常用于C),静态断言我以前在什么地方见过是这样的:

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

这工作,因为如果pred是假的,代码将最终为switch(0){case: 0: case 0:;},并且具有相同常量的两个外壳标签是错误。 In depth explanation here

+0

@Dan:看我的编辑。为什么宏有一个`sizeof(aTemp);`行? – nakiya 2011-01-28 06:11:54

+0

@Dan实际上`compile_time_check :: compile_time_check()`会编译,因为默认的构造函数可用。这就是为什么具有looong名称的结构正在被传递。 – ssmir 2011-01-28 06:16:06

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;时,它会使用这个。这种专业化有一个默认的构造函数(这是从来没有使用过),但没有构造函数,它将接受一个参数。

这样做的目的是,这是永远只能从这里使用:

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

在这种情况下,我们实例化一个tmplimpl对象与构造函数的参数。如果模板参数为true,那么这将起作用,但如果模板参数为false,则它将使用上面的只有默认ctor的专业化,而不是一个会接受参数的专业化 - 因此编译器会打印出来一个错误消息说是这样的:

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

随后sizeof(aTemp);有强迫该对象在编译时要评估的,所以我们认为这是一个编译器错误消息,而不是链接错误说compile_time_check::compile_time_check<false>()是一个悬而未决外部。