2010-09-05 34 views
8

如何在不使用C++ 0x标准的情况下实现auto关键字功能?手工制作的自动模板(不使用C++ 0x)

for(std::deque<std::pair<int, int> >::iterator it = points.begin(); 
    it != points.end(); ++it) 
{ 
    ... 
} 

也许这种类:

class AUTO 
{ 
public: 
    template <typename T1> 
    AUTO(T1); 

    template <typename T2> 
    operator T2(); 
}; 

利用这种用法:

for(AUTO it = points.begin(); it != points.end(); ++it) 
{ 
    ... 
} 

但是,T1和T2是不同的。 如何将有关T1的信息移动到运营商T2()? 真的有可能吗?

回答

12

如果库扩展很容易实现,则不需要语言扩展。有关自动提议的详细信息,请参见N1607

但是,Boost.Foreach上的article(这种做你想要的)宏可能有助于理解与这种实现相关的问题。

什么是BOOST_FOREACH?

在C++中,编写循环遍历序列迭代 是很乏味的。我们可以 或者使用迭代器,这需要 相当多的锅炉板, 或者我们可以使用std :: for_each的() 算法和我们的循环体移到 一个谓语,这并没有减少 锅炉板并迫使我们将我们的逻辑远离它将被使用的地方。 相比之下,像Perl这样的其他一些语言, 提供专用的 “foreach”构造,该构造自动执行此过程。 BOOST_FOREACH仅为 这样的C++构造。它为我们遍历序列 ,使我们免于从 直接处理迭代器 或编写谓词。

BOOST_FOREACH是专为 易于使用和效率。它不会执行 动态分配,也不会虚拟 函数调用或通过 函数指针调用,并且不会对 编译器的优化器透明,也不会调用 。这导致 近乎最佳的代码生成; BOOST_FOREACH的 性能通常在 等效手编码循环的几个百分比内。而 虽然BOOST_FOREACH是一个宏,它 是一个非常好表现。它 恰好评估其参数一次, 导致没有讨厌的惊喜。

+0

我想到只用于像foreach一样的实现。 C++ 0x的关键字auto有很多用法...感谢链接,我会读。 – k06a 2010-09-05 19:44:24

+4

@ k06a:C++强烈反对将它作为一种新的语言功能实现时,它可以在库中实现。因此,如果某种语言最终出现在语言中,您可以确信没有人找到在图书馆中正确使用它的方法。 (例如,许多其他语言都内置了std :: function和std :: bind这个语言,但它是C++中的一个库函数。) – sbi 2010-09-05 20:52:19

+1

我一直在想为什么BOOST_FOREACH是百分之几远离“手动编码”循环。 – 2010-09-05 21:21:18

10

有一个BOOST_AUTO宏或多或少做什么auto关键字......然而,只要看它的实现会告诉你,这是远不如找到一种方法,使用的C++ 0x:>

+0

感谢您的链接。读取... – k06a 2010-09-05 19:56:09

+0

另外,如果编译器不支持decltype或typeof,BOOST_AUTO将只能处理内置类型以及许多标准库类型。其他user.defined类型必须“注册”,以便BOOST_AUTO识别它们 - 如果我记得正确。 – sellibitze 2010-09-07 16:24:05

2

更直接的问题是从推导类型获取信息到数据成员声明。

class AUTO 
{ 
public: 
    template <typename T1> 
    AUTO(T1); 

    T1 state; // eg deque<...>::iterator - need this! 
}; 

这显然不会发生,因为被调用函数之前的AUTO对象必须进行分配。

鉴于typeofdecltype,但它并不难。

#define AUTO(name, initializer) typeof(initializer) name = initializer 

当然,这有很多限制。并且typeof不是标准。有了多个编译器支持,这可能会成为这些Boost工具的基础。

3

您可以使用这些宏以符合标准的方式解决此问题。

#define DEF_DED(D, E) any_base const & D = make_any_concrete((E)) 
#define DED(D, E) get_t(D, true ? ded_ty() : get_idt((E))) 

template<typename T> struct id { 
    typedef T type; 
}; 

template<typename T> 
id<T> get_idt(T t) { return id<T>(); } 

struct any_base { }; 

template<typename D> 
struct any_concrete : any_base { 
    any_concrete(D d):d(d) {} 
    mutable D d; 
}; 

template<typename T> 
any_concrete<T> make_any_concrete(T x) { return any_concrete<T>(x); } 

struct ded_ty { 
    template<typename T> 
    operator id<T>() { return id<T>(); } 
}; 

template<typename T> 
T &get_t(any_base const &b, id<T>) { return static_cast<any_concrete<T> const&>(b).d; } 

所以你的for循环变得

for(DEF_DED(it, points.begin()); 
    DED(it, points.begin()) != points.end(); 
    ++DED(it, points.begin())) 
{ 
    ... 
} 

幸得Conditional Love: FOREACH Redux,由Eric Niebler。不知道这是否真的值得:)