繁体   English   中英

使用CRTP技术确保唯一的模板参数

[英]Using CRTP technique to ensure unique template arguments

boost::units

struct my_base_dimension1 : units::base_dimension<my_base_dimension1, 1> { };  // ok
struct my_base_dimension2 : units::base_dimension<my_base_dimension2, 2> { };  // ok
struct my_base_dimension3 : units::base_dimension<my_base_dimension3, 2> { };  // error

我试图了解代码如何确保模板参数唯一。 我不明白check_base_dimension如何最终返回非零值,这会触发ordinal_has_already_been_defined<true> 我认为这与在base_dimension中重新定义的boost_units_is_registered() base_dimension ,但是我不知道如何调用friend版本。 有任何想法吗?

有问题的文件是base_dimension.hppprevent_redefinition.hpp

template<class Derived, long N,
         class = typename detail::ordinal_has_already_been_defined<
             check_base_dimension<Derived, N>::value
             >::type
         >
class base_dimension : public ordinal<N>
{
public:
    typedef base_dimension this_type;
    typedef list<dim<Derived,static_rational<1> >, dimensionless_type> dimension_type;
    typedef Derived type;

private:                                                                                                                           
    friend Derived*
    check_double_register(const units::base_dimension_ordinal<N>&)
        { return(0); }

    friend detail::yes
    boost_units_is_registered(const units::base_dimension_ordinal<N>&)
        { detail::yes result; return(result); }

    friend detail::yes
    boost_units_is_registered(const units::base_dimension_pair<Derived, N>&)
        { detail::yes result; return(result); }
};

啊哈,我相信我有。

答案在本节中:

/// Register this ordinal
        /// INTERNAL ONLY
        friend detail::yes 
        boost_units_is_registered(const units::base_dimension_ordinal&) 
        { return(detail::yes()); }

        /// But make sure we can identify the current instantiation!
        /// INTERNAL ONLY
        friend detail::yes 
        boost_units_is_registered(const units::base_dimension_pair&) 
        { return(detail::yes()); }

friend声明表明存在与那些参数匹配的函数,并返回detail::yes

当为给定的模板实例化check_base_dimensionenum时,它将查找采用这两种类型的boost_units_is_registered函数。 如果以前不存在这些模板参数的实例化,则它将找到prevent_redefinition.hpp中定义的函数,该函数返回detail::no ,但如果确实存在,则找到与返回参数的参数相匹配的函数( friend )的声明。 detail::yes

重要的是要注意,所有这些都是在编译时而不是运行时进行的。 编译器用户依赖参数的查找以找到匹配的函数。 sizeof该函数的结果只取决于该函数返回的东西-它并不需要运行,或者叫可言,它只是需要一个声明,让返回值的大小。 因此,当编译器找到friend函数时,便可以确定返回值的sizeof ,该函数实际上不需要定义。 当然,如果您尝试使用它(例如,使其实际运行),则会收到链接器错误,因为它已声明但从未定义。

结果,在编译时, sizeof()被确定为detail::yes的大小,这与detail::no的大小不同。 因此,表达式的结果为false ,因此check_base_dimension::valuefalse ,并且ordinal_has_already_been_defined的实例化未获得名为type的成员变量。

因此,编译器将引发错误,指出

detail::ordinal_has_already_been_defined<check_base_dimension<Derived, N>::value> does not have a member variable 'type'

或类似。 最后,目标得以实现:您无法使用具有相同模板参数值的类的两个实例来编译代码。 晕!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM