[英]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.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); }
};
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_dimension
的enum
时,它将查找采用这两种类型的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::value
为false
,并且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.