简体   繁体   English

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

[英]Using CRTP technique to ensure unique template arguments

From boost::units : 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

I'm trying to understand how the code ensures that template arguments are unique. 我试图了解代码如何确保模板参数唯一。 I don't understand how check_base_dimension ends up returning a non-zero, which triggers ordinal_has_already_been_defined<true> . 我不明白check_base_dimension如何最终返回非零值,这会触发ordinal_has_already_been_defined<true> I think it has something to do with boost_units_is_registered() being redefined in base_dimension , but I have no idea how the friend version gets called. 我认为这与在base_dimension中重新定义的boost_units_is_registered() base_dimension ,但是我不知道如何调用friend版本。 Any ideas? 有任何想法吗?

The files in question are base_dimension.hpp and prevent_redefinition.hpp . 有问题的文件是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); }
};

Aha, I believe I have it. 啊哈,我相信我有。

The answer is in this section: 答案在本节中:

/// 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()); }

The friend declaration indicates that a function matching those arguments exists, and returns detail::yes . friend声明表明存在与那些参数匹配的函数,并返回detail::yes

When the enum in check_base_dimension is instantiated for a given template, it looks for a boost_units_is_registered function that takes those two types. 当为给定的模板实例化check_base_dimensionenum时,它将查找采用这两种类型的boost_units_is_registered函数。 If no previous instantiation of those template parameters exists, it finds the function defined in prevent_redefinition.hpp that returns a detail::no , but if one does exist, it finds a declaration of a function (the friend ) matching those arguments that returns the detail::yes . 如果以前不存在这些模板参数的实例化,则它将找到prevent_redefinition.hpp中定义的函数,该函数返回detail::no ,但如果确实存在,则找到与返回参数的参数相匹配的函数( friend )的声明。 detail::yes

It's important to note that this is all at compile-time, not run-time. 重要的是要注意,所有这些都是在编译时而不是运行时进行的。 The compiler users argument-dependent lookup to find a matching function. 编译器用户依赖参数的查找以找到匹配的函数。 The sizeof the result of that function depends only on what the function returns – it does not need to be run or called at all, it just needs a declaration that gives the return value's size. sizeof该函数的结果只取决于该函数返回的东西-它并不需要运行,或者叫可言,它只是需要一个声明,让返回值的大小。 So when the compiler finds the friend function, it can determine the sizeof the return value then-and-there – the function need not actually have a definition. 因此,当编译器找到friend函数时,便可以确定返回值的sizeof ,该函数实际上不需要定义。 Of course, if you tried to use it (as in, have it actually run), you'd get a linker error, since it is declared but never defined. 当然,如果您尝试使用它(例如,使其实际运行),则会收到链接器错误,因为它已声明但从未定义。

As a result, the sizeof() is determined, at compile time, to be the size of a detail::yes which is distinct from the size of a detail::no . 结果,在编译时, sizeof()被确定为detail::yes的大小,这与detail::no的大小不同。 The result of the expression is thus false , and therefore check_base_dimension::value is false , and the instantiation of ordinal_has_already_been_defined does not get a member variable called type . 因此,表达式的结果为false ,因此check_base_dimension::valuefalse ,并且ordinal_has_already_been_defined的实例化未获得名为type的成员变量。

The compiler therefore throws an error stating that 因此,编译器将引发错误,指出

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

Or similar. 或类似。 In the end, the goal is achieved: you cannot compile the code with two instances of the class with the same template parameter values. 最后,目标得以实现:您无法使用具有相同模板参数值的类的两个实例来编译代码。 Huzzah! 晕!

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

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