C++11中auto关键字与表达式模板的问题

C++11标准中,auto关键字被引入以简化类型声明,它允许编译器自动推断变量的类型。然而,当auto与表达式模板(expression templates)和代理对象(proxies)一起使用时,可能会出现问题。简单地用auto替换类型可能会导致未定义行为。下面是一个示例代码,展示了这个问题:

#include <vector> #include <iostream> #include <limits> std::vector<bool> to_bits(unsigned int n) { const int bits = std::numeric_limits<unsigned int>::digits; std::vector<bool> ret(bits); for (int i = 0, mask = 1; i < bits; ++i, mask *= 2) ret[i] = (n & mask) != 0; return ret; } int main() { bool b = to_bits(42)[3]; auto a = to_bits(42)[3]; std::cout << std::boolalpha << b << std::endl; std::cout << std::boolalpha << a <<< std::endl; }

那么,如何解决这个问题呢?有关于添加一个operator auto的讨论,可以在类中定义它。然而,可能需要一段时间才能得到类似的东西。Herb Sutter在他的"Almost Always Auto"中说这是一个特性而不是一个bug,"因为有一个方便的方式来拼写'捕获列表或代理'和'解析计算',这取决于意思"。

以下是一些讨论这个问题的代码:

auto a = matrix{...}, b = matrix{...}; // some type that does lazy eval auto ab = a * b; // to capture the lazy-eval proxy auto c = matrix{ a * b }; // to force computation

这不仅可能危险,而且可能会很繁琐。如果matrix接受一些模板参数,比如维度和类型,现在有:

auto a = matrix<2, 3, double>{...}, b = matrix<3, 2, double>{...}; // some type that does lazy eval auto ab = a * b; // to capture the lazy-eval proxy auto c = matrix<3, 3, double>{ a * b }; // to force computation

在这种情况下,正在迅速失去auto的好处。是否有一些方法可以让拥有auto和表达式模板呢?这里有一个解决方案,虽然不是完美的,但认为这是在不改变语言的情况下能做的最好的事情。

将模拟operator auto:

namespace operator_auto { template <class T> struct operator_auto_type { using type = T; }; struct operator_auto_imp { template <class T> typename operator_auto_type<T>::type operator=(T &&t){ return std::forward<T>(t); } }; } namespace { operator_auto_imp _auto; }

这只是一个创建一个_auto变量的操作,当分配给它时,它返回分配的任何东西转换为另一种类型,而在默认情况下是相同的类型。然后像这样专门化operator_auto_type:

// For my::string for Motti's example namespace operator_auto { template <class T> struct operator_auto_type<my::string::concat<T>> { using type = my::string; }; } // For vector bool namespace operator_auto { template <> struct operator_auto_type<std::vector<bool>::reference> { using type = bool; }; }

现在要使用它,每当使用auto与可能产生代理的表达式时,只需要包括一个额外的分配给_auto。以下是如何使用my::string:

using operator_auto::_auto; my::string a("hello"), b(" "), c("world"), d("!"); auto s = _auto = a + b + c + d; auto a1 = _auto = a; std::cout << s << std::endl;

注意对于a1,实际上是分配给一个my::string。在这种情况下,分配给_auto将变成一个无操作。

完整的源代码可以在这里查看:。对于可运行的版本,可以查看:。

至于名字_auto,选择它是因为它很短,下划线有点暗示"flatten"或"collapse",导致一个记忆的"collapse auto",这有点暗示了想要的。然而,如果愿意,可以很容易地改变它。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485