[英]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.hpp
和prevent_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_dimension
的enum
时,它将查找采用这两种类型的boost_units_is_registered
函数。 如果以前不存在这些模板参数的实例化,则它将找到prevent_redefinition.hpp
中定义的函数,该函数返回detail::no
,但如果确实存在,则找到与返回参数的参数相匹配的函数( friend
)的声明。 detail::yes
。
重要的是要注意,所有这些都是在编译时而不是运行时进行的。 编译器用户依赖于参数的查找以找到匹配的函数。 该sizeof
该函数的结果只取决于该函数返回的东西-它并不需要运行,或者叫可言,它只是需要一个声明,让返回值的大小。 因此,当编译器找到friend
函数时,便可以确定返回值的sizeof
,该函数实际上不需要定义。 当然,如果您尝试使用它(例如,使其实际运行),则会收到链接器错误,因为它已声明但从未定义。
结果,在编译时, sizeof()
被确定为detail::yes
的大小,这与detail::no
的大小不同。 因此,表达式的结果为false
,因此check_base_dimension::value
为false
,并且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.