忽略模板特殊化并显式使用未特定化模板 (std::vector<bool>)

Ignore a template spezialization and explicitly use the unspezialized template (std::vector<bool>)

本文关键字:std vector gt lt bool 特殊化      更新时间:2023-10-16

在处理一些旧代码时,它遇到了一个用于存储一些布尔值(在类构造函数中分配并用作数组)的std::unique_ptr<bool>

当我试图用std::vector<bool>替换它时,我遇到了一个问题,因为我必须调用一个库函数,该函数需要一个计数和一个指向第一个布尔值(const bool*)的指针:std::vector<bool>有一个模板专用化,它将8个布尔值压缩为一个字节,因此如果不先解压缩数据,就不可能获得指向数据的bool*指针。

我已经通过谷歌搜索或StackOverflow文章C++11 vector<bool>性能问题(代码示例),但它们都不适合我(即,使用包含布尔值的结构可以工作,但它使我试图简化的代码更加复杂;std::valarray不提供数据()成员)

还有一篇文章"如何防止std::vector<bool>的专业化",但所有的解决方案都只有变通办法,我不相信"bool和无符号字符通常会占用相同的内存"这句话(在指向std::vector<bool<?的元素时,在编译器错误时提到)

我还检查了Alternative to vector<bool>但我们的解决方案中不使用boost,我不愿意将这种依赖添加到单一用途中。

我的问题是:是否有一种方法可以忽略模板特定化,并显式使用类型的未特定化模板

例如

#include <iostream>
template<class T>
class MyTemplate
{
public:
static const int Value = 0;
}
template<>
class MyTemplate<double>
{
public: 
static const int Value = 1;
};
int main(int argc, char **argv)
{
// How can I make MyTemplate<double> ignore the spezialization and output 0?
std::cout << "0==" << MyTemplate<double>::Value << std::endl;
return 0;
}

答案是否定的,因为无法保证存在非专用模板。

特别是,编译器对所有内置类型进行专门化是非常合理的。因此,您通常会看到一个编译时调度:每当T是内置类型时,vector<T>就会转发到__VectorImplBuiltIn<T>,而__VectorImplBuiltIn<T>则专门用于每个单独的情况。因此,vector<float>可以使用AVX一次复制4个浮点,并且vector<bool>被打包。

现在没有可移植的方法来命名特定的实现类(它实际上是一个实现细节),而且未专用的__VectorImplBuiltIn<T>甚至不会有通用实现,因为编译器供应商显然知道所有内置类型。

在这个方案中,"正常"的vector<T>将扩展到__VectorImplClassType<T>,这对于T==bool来说可能是不可用的,因为bool没有构造函数。

因此,一个完全合理的方案,其中std::vector<T>从区分有构造函数和没有构造函数的类型开始,会让你的想法变得不可能。因此,ISO C++标准不允许你想要的东西也就不足为奇了。

您可以创建一个看起来与bool行为相同的包装结构,因此不需要修改期望它是bool:的代码

struct B {
bool val;
B() {}
B(bool val): val(val) {}
operator bool&() { return val; }
operator const bool&() const { return val; }
bool* operator&() { return &val; }
const bool* operator&() const { return &val; }
};

那么以下所有情况都是可能的:

B a = true, b(0);
a || 2 == 1;
5 ^ a;
const bool& x = a;
bool* y = &a;
a &= b;
!a;

这并不是你问题的确切答案,尽管它可能是你问题的答案。

你说你正在尝试使用一个以bool *为参数的库,而你没有使用std::valarray,因为它没有data()

但是下面的不起作用吗?

#include <iostream>
#include <valarray>
using namespace std;
void doStuff(bool *x) {
*x = true;
}
int main() {
valarray<bool> v = {false,false,false,false,false,false};
doStuff(&v[2]);
for (bool b : v) {
cout << b << endl;
}
//if you *really* want data(), &v[0] does the same
return 0;
}

实时演示

请注意,valarray保证具有连续内存。


另一种选择是创建一个替换容器,这里给出了一个名为SimpleVector的示例,它只需要添加一个简单的头文件,代码的海报引用了Mark Allen Weiss的一本书。

在该实施方式中,CCD_ 25的行为与CCD_ 26相同。

尽管代码是c++11之前的代码,所以它没有实现&&的构造函数。