Mat*_* M. 9 c++ metaprogramming
免责声明:问题与继承而不是typedef完全不同,到目前为止我找不到任何类似的问题
我喜欢玩c ++模板元编程(在家里大多数情况下,我有时会在工作中轻轻地介绍它,但我不希望程序只对任何不打扰学习它的人都可读),但是我一直在每当出现问题时都会被编译器错误搞清楚.
问题是当然c ++模板元编程基于模板,因此当你在深层嵌套的模板结构中得到编译器错误时,你必须在10行错误消息中挖掘你的方式.我甚至习惯于在文本编辑器中复制/粘贴消息,然后缩进消息以获得一些结构,直到我了解实际发生的事情,这增加了一些跟踪错误本身的工作.
据我所知,问题主要是由于编译器以及它如何输出typedef(还有其他问题,如嵌套的深度,但它并不是编译器的错误).即将发布的C++ 0x宣布了可变参数模板或类型演绎(自动)等酷炫功能,但我真的希望有更好的错误消息来启动.使用模板元编程可能会让人感到痛苦,而且我确实想知道当更多人真正进入它们时会发生什么.
我已经替换了代码中的一些typedef,而是使用了继承.
typedef partition<AnyType> MyArg;
struct MyArg2: partition<AnyType> {};
Run Code Online (Sandbox Code Playgroud)
这不是更多的字体,我认为这并不是那么可读.实际上它甚至可能更具可读性,因为它保证声明的新类型看起来接近左边距,而不是在右边的未确定偏移处.
然而,这涉及另一个问题.为了确保我没有做任何愚蠢的事情,我经常编写模板函数/类,如下所示:
template <class T> T& get(partition<T>&);
Run Code Online (Sandbox Code Playgroud)
这样我就确定只能为合适的对象调用它.
特别是当重载运算符(如operator +)时,您需要某种方法来缩小运算符的范围,或者冒着为int调用它的风险.
但是,如果这适用于typedef类型,因为它只是一个别名.它肯定不适用于继承......
对于功能,可以简单地使用CRTP
template <class Derived, class T> partition;
template <class Derived, class T> T& get(partition<Derived,T>&);
Run Code Online (Sandbox Code Playgroud)
这允许知道在编译器使用公共继承之前用于调用方法的"真实"类型.应该注意,这减少了必须调用此特定函数的机会,因为编译器必须执行转换,但到目前为止我从未注意到任何问题.
此问题的另一个解决方案是向我的类型添加"标记"属性,以区分它们,然后依靠SFINAE.
struct partition_tag {};
template <class T> struct partition { typedef partition_tag tag; ... };
template <class T>
typename boost::enable_if<
boost::same_type<
typename T::tag,
partition_tag
>,
T&
>::type
get(T&)
{
...
}
Run Code Online (Sandbox Code Playgroud)
它需要更多的打字,特别是如果一个人在不同的地方声明并定义了函数/方法(如果我不打扰我的界面很快就会混乱).但是,当涉及到类时,由于没有执行类型转换,它确实变得更复杂:
template <class T>
class MyClass { /* stuff */ };
// Use of boost::enable_if
template <class T, class Enable = void>
class MyClass { /* empty */ };
template <class T>
class MyClass <
T,
boost::enable_if<
boost::same_type<
typename T::tag,
partition_tag
>
>
>
{
/* useful stuff here */
};
// OR use of the static assert
template <class T>
class MyClass
{
BOOST_STATIC_ASSERT((/*this comparison of tags...*/));
};
Run Code Online (Sandbox Code Playgroud)
我倾向于使用'enable_if'更多的'静态断言',我认为当我在一段时间后回来时它更具可读性.
好吧,基本上我还没有想到我的想法,我仍在尝试介绍这里暴露的不同技术.
你使用typedef还是继承?如何限制方法/函数的范围或以其他方式控制提供给它们(以及类)的参数类型?
当然,如果可能的话,我会更喜欢个人喜好.如果有合理的理由使用特定的技术,我宁愿知道它!
编辑:
我正在浏览stackoverflow,刚从Boost.MPL发现这个perl我完全忘记了:
这个想法是你给宏3个参数:
它可能对代码自我文档和更好的错误输出都有很大帮助.
您想要做的是显式检查作为模板参数传递的类型是否提供必要的概念。由于缺少被 C++0X 抛弃的概念功能(因此成为 C++1X 的罪魁祸首之一),因此很难进行适当的概念检查。自 20 世纪 90 年代以来,人们曾多次尝试在没有语言支持的情况下创建概念检查库,但基本上,所有这些所取得的成就都是为了表明,为了做得正确,概念需要成为核心语言的一个功能,而不是成为核心语言的一个功能。比图书馆独有的功能。
我不认为你的推导而不是typedef使用的想法enable_if很有吸引力。正如您自己所说,它通常只是为了更好的编译器错误消息而掩盖实际代码。
我发现静态断言要好得多。它不需要改变实际的代码,我们都习惯在算法中进行断言检查,并且如果我们想理解实际的算法,就学会在心里跳过它们,它可能会产生更好的错误消息,并且它将延续到 C ++1X 更好,这将static_assert在语言中内置一个(完全包含类设计者提供的错误消息)。(如果可用的话,我怀疑BOOST_STATIC_ASSERT只是使用内置的。)static_assert